卓越飞翔博客卓越飞翔博客

卓越飞翔 - 您值得收藏的技术分享站
技术文章35393本站已运行395

为什么 net/http 不考虑超过 30 秒的超时持续时间?

为什么 net/http 不考虑超过 30 秒的超时持续时间?

php小编香蕉在探讨网络请求中的超时持续时间时发现,为什么net/http在设计中没有考虑超过30秒的超时时间限制?超时时间是指在发送请求后,如果在指定时间内没有收到响应,就会认为请求失败。在网络请求中,超时时间的设置是非常重要的,过短可能导致请求失败,过长则会浪费资源。通过分析,主要原因是在设计时考虑到了性能和资源的平衡,以及网络环境的不确定性。接下来,我们将详细解答这个问题。

问题内容

使用 golang 1.20.1。

在golang的net/http和context包中,我无法设置超过三十秒的超时。设置较短的超时效果很好,例如

代码:

log.infof("elasticsearch url is %v", elasticsearchurl)
    client := &http.client{timeout: time.duration(time.second * 60)}
    req, err := http.newrequest("get", listbackupsurl, nil)
    if err != nil {
        internalerror(w, fmt.sprintf("error creating request: %v", err))
        return
    }
    req.setbasicauth(username, password)
    resp, err := client.do(req)
    if err != nil {
        // handle error
        internalerror(w, fmt.sprintf("error accessing elasticsearch: %v", err))
        return
    }

日志:

i0503 23:01:55.973821       1 somecode.go:85] url is http://elasticsearch.example.ingest:9200
e0503 23:02:25.976345       1 caller_handler.go:63] 500 internal server error: error accessing elasticsearch: get "http://elasticsearch.example.ingest:9200/_cat/snapshots/object-store-repo?v&s=id": dial tcp 1.2.3.4:9200: i/o timeout

超时时间是三十秒,而不是六十秒。

如果我使用 http.newrequestwithcontext(...) 并使用设置相同超时的上下文,我会得到相同的行为:

代码:

log.infof("elasticsearch url is %v", elasticsearchurl)
    ctx, cancel := context.withtimeout(context.background(), time.duration(time.second * 60)) 
    defer cancel()
    req, err := http.newrequestwithcontext(ctx, "get", listbackupsurl, nil)
    if err != nil {
        internalerror(w, fmt.sprintf("error creating request: %v", err))
        return
    }
    req.setbasicauth(username, password)
    resp, err := client.do(req)
    if err != nil {
        // handle error
        internalerror(w, fmt.sprintf("error accessing elasticsearch: %v", err))
        return
    }

日志:

i0503 23:31:10.941169       1 somecode.go:85] elasticsearch url is http://elasticsearch.example.ingest:9200
e0503 23:31:40.941642       1 caller_handler.go:63] 500 internal server error: error accessing elasticsearch: get "http://elasticsearch.example.ingest:9200/_cat/snapshots/object-store-repo?v&s=id": dial tcp 1.2.3.4:9200: i/o timeout

但是,如果我在任一方法中将超时更改为三秒 (time.duration(time.second * 3)),它将按预期工作:

I0503 23:44:17.622121       1 somecode.go:85] Elasticsearch URL is http://elasticsearch.example.ingest:9200
E0503 23:44:20.624795       1 caller_handler.go:63] 500 Internal Server Error: error accessing elasticsearch: Get "http://elasticsearch.example.ingest:9200/_cat/snapshots/object-store-repo?v&s=id": context deadline exceeded (Client.Timeout exceeded while awaiting headers)

解决方法

我会隔离问题以消除可能性,从而帮助缩小导致问题发生的原因。如果可能,请使用一小段代码,这样您就可以只处理您想要的内容。

要测试您的基础设施,httpstat 将帮助您模拟远程超时。示例:

func main() {

    client := &http.Client{Timeout: time.Duration(time.Second * 200)}
    req, err := http.NewRequest("GET", "https://www.php.cn/link/1a59ef90d1ea801448e1567d0896a99f/504?sleep=120000", nil)
    if err != nil {
        log.Fatal(err)
        return
    }

    resp, err := client.Do(req)
    if err != nil {
        log.Fatal(err)
        return
    }

    fmt.Println(resp)
}

如果您此时收到 dial tcp ip:port: i/o timeout timeout,那么您需要检查您的操作系统和防火墙。无论您在 go 中设置什么超时,都应该覆盖操作系统默认值,如果您以这种方式超时,则可能是防火墙(本地或远程)导致了这种情况。

或者,如果您能够从外部连接,则 es 可能会超时,尽管根据文档,您应该预期会直接来自 es 的信息错误。您可以直接在 url 中设置 es 的超时 并对其进行测试。

希望这有帮助。

卓越飞翔博客
上一篇: 如何使用泛型 Go 实例化类型参数的非零指针?
下一篇: 返回列表
留言与评论(共有 0 条评论)
   
验证码:
隐藏边栏