146

我在 Go 中制作了一个 URL 获取器,并有一个要获取的 URL 列表。我向http.Get()每个 URL 发送请求并获得它们的响应。

resp,fetch_err := http.Get(url)

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

我怎样才能做到这一点?

4

7 回答 7

321

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

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

这对我来说已经成功了。

于 2014-08-16T22:10:17.533 回答
55

您需要使用您自己的Transport设置您自己的Client ,它使用一个自定义的 Dial 函数,该函数环绕DialTimeout

像(完全未经测试这样的东西:

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")
}
于 2013-06-03T11:40:24.067 回答
34

要添加到 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()

于 2013-06-05T02:33:37.573 回答
32

如果您想按请求执行此操作,则为简洁起见忽略错误处理:

ctx, cncl := context.WithTimeout(context.Background(), time.Second*3)
defer cncl()

req, _ := http.NewRequestWithContext(ctx, http.MethodGet, "https://google.com", nil)

resp, _ := http.DefaultClient.Do(req)
于 2018-08-27T21:41:47.147 回答
10

一种快速而肮脏的方式:

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

这是在没有任何协调的情况下改变全局状态。然而,对于您的 url 提取器来说,它可能没问题。否则创建一个私有实例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)
...

以上没有经过测试。

于 2013-06-03T11:36:04.797 回答
1

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

于 2014-01-21T19:42:44.060 回答
-1
timeout := time.Duration(5 * time.Second)
transport := &http.Transport{Proxy: http.ProxyURL(proxyUrl), ResponseHeaderTimeout:timeout}

这可能会有所帮助,但请注意ResponseHeaderTimeout仅在建立连接后才开始。

于 2019-06-28T21:50:53.767 回答