英文:
how to catch "http: server closed idle connection" error
问题
在我的Go应用程序中,我遇到了以下错误:"http: server closed idle connection"。我想要捕捉这个错误,并在遇到时重试我的HTTP连接。
我发现这个错误来自"net/http"包,更具体地说是来自传输实现。它在这里被定义:链接
我将它包装在url.Error
中,但这是我能找到的全部信息。你知道我如何实际捕捉这个错误吗?
编辑:
我正在使用elastic search client,它又使用了net/http
。从客户端那里,我得到了上述提到的错误,并希望在遇到临时错误时重试我的elastic search请求。目前,我捕捉临时错误的方式是:
if urlErr, ok := err.(*url.Error); ok && (urlErr.Temporary() || urlErr.Err == io.EOF) {
return retryRequest()
}
英文:
In my go application I am getting the following error: "http: server closed idle connection". I would like to catch it and retry my http connection if it's encountered.
I found that this error comes from the "net/http" package and furthermore from the transport implementation. In particular it's defined here
I get it wrapped in url.Error
but this is all I was able to find out. Do you know how I can actually catch this error?
Edit:
I am using elastic search client, which in turn is using the net/http
. From the client I get the above mentioned error and would like to retry my elastic search request as being transient. For now the way I am catching transient errors is:
if urlErr, ok := err.(*url.Error); ok && (urlErr.Temporary() || urlErr.Err == io.EOF) {
return retryRequest()
}
答案1
得分: 5
在net/http/transport.go
中的注释(位于这里)中提到:
if err == errServerClosedIdle {
// The server replied with io.EOF while we were trying to
// read the response. Probably an unfortunately keep-alive
// timeout, just as the client was writing a request.
return true
}
如果在读取响应时出现errServerClosedIdle
错误,那么服务器可能在客户端发送请求时发生了不幸的 keep-alive 超时。在这种情况下,Go 会尝试重新发送请求,如果找到非空的http.Request.GetBody
(位于这里),所以我认为重新发送请求(或提供GetBody
函数)是符合预期的。
至于导致错误的原因,你可能需要检查服务器的 keep-alive 功能,我猜测服务器可能会过早地发送 TCP 连接重置(被解释为io.EOF
)。你可以尝试禁用 keep-alive,看看是否会有任何变化。
英文:
Comments in net/http/transport.go
say this (located here):
if err == errServerClosedIdle {
// The server replied with io.EOF while we were trying to
// read the response. Probably an unfortunately keep-alive
// timeout, just as the client was writing a request.
return true
}
Go will attempt to retry the request if it finds a non-nil http.Request.GetBody
(found here), so I think it is expected to retry the request (or provide a GetBody
function).
As for the leading error cause, you might want to check server's keep-alive functionality, my guess is that server is sending TCP connection reset (interpreted as io.EOF
) prematurely. You might want to try disabling keep-alives and see if that changes anything.
答案2
得分: 2
正如Gray Fox提到的,Go通常会重试这些请求。然而,对于那些不是“幂等”的请求,情况就不同了。我在进行一些POST
请求时遇到了一些错误,在搜索过程中我找到了这个Github问题,其中提到:
>HTTP传输通常会重试这些请求,但由于它们是POST请求,它们不是幂等的,Go保守地认为重试它们可能是不安全的。
在问题的后面,有人提到许多银行API使用某种变体的Idempotent-Key
头来使它们“安全”。Stripe是一个使用该头的公司,他们的API文档中对此有如下说明:
>API支持幂等性,以便在不意外执行相同操作的情况下安全地重试请求。
所以,这就是该头的用途。
简而言之,如果你希望Go的HTTP传输重试POST请求(以及其他非幂等的请求),你需要包含Idempotency-Key
或X-Idempotency-Key
头。这并不一定使这些请求变得幂等,但从net/http
的角度来看,它们可以被重试。
链接:
-
源代码检查Idempotency-Key头 - https://github.com/golang/go/blob/2cd2ff6f564dce5be0c4fb7f06338ff7af3fc9a9/src/net/http/request.go#L1401)
-
我找到这些信息的Github问题:https://github.com/golang/go/issues/19943
英文:
As Gray Fox mentioned, Go will usually retry these requests. However, this is not the case for requests that aren't "idempotent". I was running into a few of these errors on POST
requests, and after searching around I found this Github issue that says:
>The HTTP Transport would normally retry those requests, but because they're POST requests they're not idempotent and Go conservatively assumes it might be unsafe to retry them.
Later in the issue someone mentioned that many banking APIs use some variant of the Idempotent-Key
header to make them "safe". Stripe is a company that uses that header, and this is what their API docs say about it:
>The API supports idempotency for safely retrying requests without accidentally performing the same operation twice.
So there you go, that's what the header is for.
In short, if you want Go's HTTP Transport to retry POST requests (and other non-idempotent requests), you need to include either the Idempotency-Key
or X-Idempotency-Key
header. That doesn't necessarily make those requests idempotent, but it will make them retry-able from net/http
's perspective.
Links:
-
Source code check for the Idempotency-Key headers - https://github.com/golang/go/blob/2cd2ff6f564dce5be0c4fb7f06338ff7af3fc9a9/src/net/http/request.go#L1401)
-
Github issue where I found this information: https://github.com/golang/go/issues/19943
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论