我在使用 CouchDB 和 Golang 时遇到了一个令人烦恼的问题。当向 CouchDB 发送具有相对较大 Body 大小的 POST/PUT 请求时(阈值似乎约为 8000 字节左右),连接超时,并且我从 Go 收到“tcp:使用关闭的网络连接”错误。
最终(一两秒后),CouchDB 发送 500 响应以及:
{"error":"unknown_error", "reason": "noproc"}
在体内。 couchdb 日志还写入了堆栈跟踪:
Stacktrace: [{couch_db,collect_results,3,
[{file,"couch_db.erl"},{line,833}]},
{couch_db,write_and_commit,4,
[{file,"couch_db.erl"},{line,845}]},
{couch_db,update_docs,4,
[{file,"couch_db.erl"},{line,782}]},
{couch_db,update_doc,4,
[{file,"couch_db.erl"},{line,426}]},
{couch_httpd_db,update_doc,6,
[{file,"couch_httpd_db.erl"},{line,753}]},
{couch_httpd_db,do_db_req,2,
[{file,"couch_httpd_db.erl"},{line,234}]},
{couch_httpd,handle_request_int,5,
[{file,"couch_httpd.erl"},{line,318}]},
{mochiweb_http,headers,5,
[{file,"mochiweb_http.erl"},{line,94}]}]
因此,我编写了一个快速单元测试来复制该问题(并确保不是我的包装器导致了问题)。我这样提出请求:
client := &http.Client{}
req, err := http.NewRequest(
"PUT",
"http://localhost:5984/unittestdb/testdocid1",
bytes.NewReader(testBody1), //testBody1 is 10000 bytes of json object
)
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Accept", "application/json")
resp, err := client.Do(req)
这复制了这个问题...所以我尝试将一个大的 json 文档 curl 到 couchdb。 这有效。
因此,我启动了wireshark,检查了我的代码向CouchDB 发出的请求,并将其与curl 发送的请求进行了比较。我注意到 Curl 请求中多了一个 header :
Expect: 100-continue
我必须查一下那个标题,因为我不记得以前见过(或者也许我只是不必处理)那个标题。于是我在 google 上搜索了一下 Golang http 客户端是否支持 Expect/Continue 功能,结果发现:https://github.com/golang/go/issues/3665
所以 Go 不支持它,并且至少在 1.6 之前不会支持。所以我认为这一定是一件晦涩的事情,而不是我的问题的根源。我花了几个小时随机尝试 http.Client、Transport 等其他内容。
最终,我在 Go 中的 http 请求中手动设置了“Expect: 100-continue” header (如果主体大小超过特定大小),并且......它起作用了。没有超时,没有错误,没有 couchdb 将堆栈跟踪记录到日志中。
现在我很困惑,如果 Go 不支持这个,它是如何工作的?我这样做只是掩盖问题吗?或者我可以耸耸肩继续前进吗?
我怀疑 CouchDB 端存在问题,也许我缺少配置设置?
最佳答案
我不知道答案,但我认为对你来说最关键的规范是 RFC 2616 section 8.2.3 。整个部分很有趣,但尤其是这个:
"There is an exception to this rule: for compatibility with RFC 2068, a server MAY send a 100 (Continue) status in response to an HTTP/1.1 PUT or POST request that does not include an Expect request-header field with the "100-continue" expectation. This exception, the purpose of which is to minimize any client processing delays associated with an undeclared wait for 100 (Continue) status, applies only to HTTP/1.1 requests, and not to requests with any other HTTP-version value."
听起来您陷入了 Go 缺少的 100-Continue 实现和 CouchDB 方面的某种极端情况之间的困境。 (无论客户端的行为如何,我认为 500 内部错误不是服务器的适当响应。)
如果 Go 客户端允许您设置的话,我会尝试使用 HTTP/1.0 作为解决方法。
关于http - 从 Go 到 CouchDB 的大型 PUT 请求,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30541591/