Как установить тайм-аут для http.Получить () запросы в Golang?


Я делаю url fetcher в Go и есть список URL-адресов для извлечения. Я посылаю http.Get() запросы к каждому URL и получить их ответ.

resp,fetch_err := http.Get(url)

Как я могу установить пользовательский тайм-аут для каждого запроса GET? (Время по умолчанию очень долго, и это делает мой fetcher очень медленным.) Я хочу, чтобы мой fetcher имел тайм-аут около 40-45 секунд, после чего он должен вернуть "время ожидания запроса" и перейти к следующему URL.

Как я могу этого достичь?

6 75

6 ответов:

видимо в Go 1.3 http.Клиент имеет поле тайм-аута

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

что сделал трюк для меня.

вам нужно настроить свой собственный клиент своими транспорт который использует a пользовательская функция набора, которая обертывает 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")
}

чтобы добавить к ответу Волкера, если вы также хотите установить тайм-аут чтения/записи в дополнение к тайм-ауту подключения, вы можете сделать что-то вроде следующего

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()

быстрый и грязный способ:

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

это мутация глобального состояния без какой-либо координации. Тем не менее, это может быть возможно хорошо для вашего url fetcher. В противном случае создайте частный экземпляр 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)
...

ничего выше не было проверено.

вы можете использовать https://github.com/franela/goreq который обрабатывает тайм-ауты в моде и простым способом.

Если вы хотите сделать это по запросу, обработка err игнорируется для краткости:

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