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

我在Go中创build一个URL获取器,并获取要获取的URL列表。 我发送http.Get()请求到每个URL并获得他们的回应。

 resp,fetch_err := http.Get(url) 

我如何设置每个Get请求的自定义超时? (默认时间非常长,这使得我的fetcher真的很慢。)我希望我的fetcher有大约40-45秒的超时时间,之后它应该返回“请求超时”并转到下一个URL。

我怎样才能做到这一点?

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

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

这对我来说是个诀窍。

您需要使用您自己的传输设置您自己的客户端 ,该客户端使用包含DialTimeout的自定义拨号function。

像(完全未经testing ) 这样的东西:

 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") } 

要添加到沃尔克的答案,如果你还想设置连接超时之外的读/写超时,你可以做下面的事情

 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), }, } } 

此代码已经过testing,正在生产中。 完整的testing要点可以在这里https://gist.github.com/dmichael/5710968

请注意,您将需要为每个请求创build一个新的客户端,因为conn.SetDeadlinetime.Now()

一个快速和肮脏的方式:

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

这是改变全球国家没有任何协调。 然而,它可能可以为您的url fetcher好。 否则,创build一个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) ... 

以上没有任何testing。

最后,我结束了对所有需要超时的请求使用此实用程序function。 由于某些原因,@sparrovv代码出现了。

 // reqType is one of HTTP request strings (GET, POST, PUT, DELETE, etc.) func DoRequest(reqType string, url string, headers map[string]string, data []byte, timeoutSeconds int) (int, []byte, map[string][]string, error) { var reader io.Reader if data != nil && len(data) > 0 { reader = bytes.NewReader(data) } req, err := http.NewRequest(reqType, url, reader) if err != nil { return 0, nil, nil, err } // I strongly advise setting user agent as some servers ignore request without it req.Header.Set("User-Agent", "YourUserAgentString") if headers != nil { for k, v := range headers { req.Header.Set(k, v) } } var ( statusCode int body []byte timeout time.Duration ctx context.Context cancel context.CancelFunc header map[string][]string ) timeout = time.Duration(time.Duration(timeoutSeconds) * time.Second) ctx, cancel = context.WithTimeout(context.Background(), timeout) defer cancel() err = httpDo(ctx, req, func(resp *http.Response, err error) error { if err != nil { return err } defer resp.Body.Close() body, _ = ioutil.ReadAll(resp.Body) statusCode = resp.StatusCode header = resp.Header return nil }) return statusCode, body, header, err }