如何捕获 “http: server closed idle connection” 错误。

huangapple go评论89阅读模式
英文:

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-KeyX-Idempotency-Key头。这并不一定使这些请求变得幂等,但从net/http的角度来看,它们可以被重试。

链接:

英文:

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:

huangapple
  • 本文由 发表于 2017年3月17日 08:46:01
  • 转载请务必保留本文链接:https://go.coder-hub.com/42847294.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定