web-dev-qa-db-ja.com

Golangでhttp.Get()リクエストのタイムアウトを設定するにはどうすればよいですか?

GoでURLフェッチャーを作成しており、フェッチするURLのリストがあります。 http.Get()リクエストを各URLに送信し、そのレスポンスを取得します。

resp,fetch_err := http.Get(url)

Getリクエストごとにカスタムタイムアウトを設定するにはどうすればよいですか? (デフォルトの時間は非常に長いため、フェッチャーは非常に遅くなります。)フェッチャーのタイムアウトを約40〜45秒にしてから、「リクエストがタイムアウトしました」を返し、次のURLに移動する必要があります。

どうすればこれを達成できますか?

89
pymd

Go 1.3ではどうやら http.Client にはタイムアウトフィールドがあります

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

これでうまくいきました。

230
sparrovv

独自の Client を独自の Transport に設定する必要があります。これは DialTimeout をラップするカスタムダイヤル機能を使用します。

(completelyuntested)のようなもの 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")
}
52
Volker

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

このコードはテスト済みで、本番環境で動作しています。テスト付きの完全なGistはここから入手できます https://Gist.github.com/dmichael/5710968

time.Now()から将来のポイントを参照するconn.SetDeadlineがあるため、リクエストごとに新しいクライアントを作成する必要があることに注意してください

29
dmichael

リクエストごとに実行する場合、簡潔にするためにエラー処理は無視されます。

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))
10
Chad Grant

迅速で汚い方法:

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

上記のテストは行われていません。

8
zzzz

https://github.com/franela/goreq を使用することができます。これは、タイムアウトを簡単な方法で処理します。

1
marcosnils
timeout := time.Duration(5 * time.Second)
transport := &http.Transport{Proxy: http.ProxyURL(proxyUrl), ResponseHeaderTimeout:timeout}

これは役立つかもしれませんが、ResponseHeaderTimeoutは接続が確立された後にのみ開始されることに注意してください。

0
T.Max