首页 文章

如何在Golang中为http.Get()请求设置超时?

提问于
浏览
76

我在Go中创建一个URL提取器,并有一个要获取的URL列表 . 我向每个URL发送 http.Get() 请求并获取其响应 .

resp,fetch_err := http.Get(url)

如何为每个Get请求设置自定义超时? (默认时间很长,这使得我的提取器非常慢 . )我希望我的提取器有超过40-45秒的超时时间,之后它应该返回“请求超时”并继续下一个URL .

我怎样才能做到这一点?

6 回答

  • 8

    显然在Go 1.3 http.Client中有Timeout字段

    timeout := time.Duration(5 * time.Second)
    client := http.Client{
        Timeout: timeout,
    }
    client.Get(url)
    

    这对我来说已经成功了 .

  • 52

    您需要使用自己的Transport设置自己的Client,它使用自定义拨号功能,包含DialTimeout .

    像(完全未经测试的)this

    var timeout = time.Duration(2 * time.Second)
    
    func dialTimeout(network, addr string) (net.Conn, error) {
        return net.DialTimeout(network, addr, timeout)
    }
    
    func main() {
        transport := http.Transport{
            Dial: dialTimeout,
        }
    
        client := http.Client{
            Transport: &transport,
        }
    
        resp, err := client.Get("http://some.url")
    }
    
  • 1

    要添加到Volker的答案,如果除了连接超时之外还要设置读/写超时,您可以执行以下操作

    package httpclient
    
    import (
        "net"
        "net/http"
        "time"
    )
    
    func TimeoutDialer(cTimeout time.Duration, rwTimeout time.Duration) func(net, addr string) (c net.Conn, err error) {
        return func(netw, addr string) (net.Conn, error) {
            conn, err := net.DialTimeout(netw, addr, cTimeout)
            if err != nil {
                return nil, err
            }
            conn.SetDeadline(time.Now().Add(rwTimeout))
            return conn, nil
        }
    }
    
    func NewTimeoutClient(connectTimeout time.Duration, readWriteTimeout time.Duration) *http.Client {
    
        return &http.Client{
            Transport: &http.Transport{
                Dial: TimeoutDialer(connectTimeout, readWriteTimeout),
            },
        }
    }
    

    此代码已经过测试并正在 生产环境 中 . 这里有完整的测试要点https://gist.github.com/dmichael/5710968

    请注意,您需要为每个请求创建一个新客户端,因为 conn.SetDeadline 将来引用一个点 time.Now()

  • 3

    快速而肮脏的方式:

    http.DefaultTransport.(*http.Transport).ResponseHeaderTimeout = time.Second * 45
    

    这是在没有任何协调的情况下改变全球状态 . 但是你的网址提取器可能还可以 . 否则创建一个 http.RoundTripper 的私有实例:

    var myTransport http.RoundTripper = &http.Transport{
            Proxy:                 http.ProxyFromEnvironment,
            ResponseHeaderTimeout: time.Second * 45,
    }
    
    var myClient = &http.Client{Transport: myTransport}
    
    resp, err := myClient.Get(url)
    ...
    

    以上没有测试过 .

  • 27

    如果您希望按请求执行此操作,则会因为简洁而忽略错误处理:

    ctx, cncl := context.WithTimeout(context.Background(), time.Second*3)
    defer cncl()
    
    req, _ := http.NewRequest(http.MethodGet, "https://google.com", nil)
    
    resp, _ := http.DefaultClient.Do(req.WithContext(ctx))
    
  • 202

    您可以使用https://github.com/franela/goreq以时尚和简单的方式处理超时 .

相关问题