http - 从 Go 到 CouchDB 的大型 PUT 请求

标签 http go couchdb

我在使用 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/

相关文章:

javascript - CouchDB 不区分大小写和 OR 选项,就像在 mysql 中一样

xml - 通过命令行通过 CURL 将 XML 文件上传到 CouchDB

android - 使用 CouchDB Android 的用户身份验证

javascript - 与浏览器相比,通过 Node.js 的 HTTP 请求延迟

python - 请求发布到 imgur

python - 如何使用 MITMProxy 通过代理正确转发请求?

performance - 没有外部依赖的高性能网络蜘蛛

iOS - NSDataDetector : Why does url missing '.com' (http://google) return as valid URL?

go - 如何释放内存或删除由 http.ParseMultipartForm 创建的临时文件?

go - 将 map 分配给 Golang 中的 map