net/http vs curl-为什么要在curl不存在的地方进行超时?

net/http vs curl-为什么要在curl不存在的地方进行超时?,curl,go,timeout,Curl,Go,Timeout,我有一段代码检查http/s端点的状态和加载时间。然后,对于每个顶级页面,im检查level-1 HREF,以检查页面引用的所有内容是否也加载了200 (我检查了50个顶级页面,每个顶级页面平均有8个链接) 我通过一些goroutine(25)和waitgroup检查顶级页面。对于1级页面,我尝试了另一个gouroutines+waitgroup,然后是一个直接的forloop(只是为了比较) 在这些1级页面上,我收到了很多“等待标题时超出CLient.Timeout”错误。当我抓取这样一个ur

我有一段代码检查http/s端点的状态和加载时间。然后,对于每个顶级页面,im检查level-1 HREF,以检查页面引用的所有内容是否也加载了200

(我检查了50个顶级页面,每个顶级页面平均有8个链接)

我通过一些goroutine(25)和waitgroup检查顶级页面。对于1级页面,我尝试了另一个gouroutines+waitgroup,然后是一个直接的forloop(只是为了比较)

在这些1级页面上,我收到了很多“等待标题时超出CLient.Timeout”错误。当我抓取这样一个url,并立即使用curl重试时,它就会完全加载(使用curl)

在页眉上超时的页面是js、png、gif和html的混合体。当我手动卷曲它时,常规的东西工作得很好,但从一开始就失败了

下面是我调用的获取页面内容的函数

func (t Target) getContents(timeout int64) (string, string, string) {
    var contents []byte
    statusCode := "0"
    errorLabel := "no_error"

    tr := &http.Transport{
        TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
        //      Dial: (&net.Dialer{
        //          Timeout:   15 * time.Second,
        //          KeepAlive: 15 * time.Second,
        //      }).Dial,
        TLSHandshakeTimeout:   10 * time.Second,
        ResponseHeaderTimeout: 10 * time.Second,
        ExpectContinueTimeout: 1 * time.Second,
    }

    client := &http.Client{Transport: tr, Timeout: time.Duration(timeout) * time.Second}

    url := t.getPageURL()
    req, err := http.NewRequest("GET", url, nil)
    if err != nil {
        log.Error("Error while creating the request| ", err)
        errorLabel = "cant_create_request"
    } else {
        //req.Header.Add("cache-control", "no-cache")
        if t.Agent != "" {
            req.Header.Set("User-Agent", t.Agent)
        }
        if t.SourceIP != "" {
            req.Header.Set("X-Forwarded-For", t.SourceIP)
        }
        if t.Host != "" {
            req.Header.Set("Host", t.Host)
            req.Host = t.Host
        }
        response, err := client.Do(req)
        if err != nil {
            log.Error("Error while doing the request| ", err.Error())
            errorLabel = "cant_do_request"
        } else {
            defer response.Body.Close()
            statusCode = strconv.Itoa(response.StatusCode)
            contents, err = ioutil.ReadAll(response.Body)
            if err != nil {
                log.Error("Error while reading the response| ", err)
                errorLabel = "cant_read_response"

            }
        }
    }
    return string(contents), statusCode, errorLabel
}

这应该是一个评论,而不是一个答案,但我没有足够的观点来评论:(

也许您应该尽量不要在每个请求上定义tr和client

如果在目标上同时启动多个并行请求,则可能会出现问题,具体取决于目标服务器和客户机系统。这可以解释为什么一个单独的测试请求在启动后就可以了

最后,我根本不是go专家,但我认为您应该避免使用nil的if/else:

req, err := http.NewRequest("GET", url, nil)
if err != nil {
    log.Error("Error while creating the request| ", err)
    errorLabel = "cant_create_request"
} else {
   ...
}
return string(contents), statusCode, errorLabel
难道不是:

req, err := http.NewRequest("GET", url, nil)
if err != nil {
    log.Error("Error while creating the request| ", err)
    return string(contents), statusCode, "cant_create_request" //return nil instead ?
}
...
return string(contents), statusCode, errorLabel

到了很多“如果水平”很难阅读并且容易出错。

这里没有足够的信息,但是一个坏了的ipv6网络会这样。无论如何,你应该在拨号程序中启用
双堆栈
,这将解决这个问题。哦,永远不要丢弃
http.Transport
,这将导致连接泄漏。看来主持人删除了编辑我的评论-是的,我是配置错误的办公网络的受害者。部署在“适当”上位置,导出器不再计时。修复
http.Transport
的不当使用,并将
DualStack
添加到拨号器中,对您仍有好处。软件包文档非常详尽,请查看推荐默认值的定义。不丢弃传输很容易;不要这样做,只需重新使用即可它(如果不做任何更改,也重用客户端)。