Pertanyaan Bagaimana mengatur batas waktu untuk permintaan http.Get () di Golang?


Saya membuat fetcher URL di Go dan memiliki daftar URL untuk diambil. saya kirim http.Get() permintaan ke setiap URL dan dapatkan tanggapannya.

resp,fetch_err := http.Get(url)

Bagaimana cara menetapkan batas waktu kustom untuk setiap permintaan Dapatkan? (Waktu default sangat panjang dan itu membuat pengumbar saya benar-benar lambat.) Saya ingin agar pengupas saya memiliki batas waktu sekitar 40-45 detik setelah itu ia harus kembali "meminta waktu habis" dan beralih ke URL berikutnya.

Bagaimana saya bisa mencapai ini?


74
2018-06-03 11:06


asal


Jawaban:


Ternyata di Go 1.3 http.Client memiliki bidang Timeout

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

Itu sudah berhasil untuk saya.


194
2017-08-16 22:10



Anda perlu mengatur sendiri Klien dengan milikmu sendiri Mengangkut yang menggunakan Fungsi Kustom Dial yang membungkus DialTimeout.

Sesuatu seperti (sepenuhnya belum dicoba) ini:

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
2018-06-03 11:40



Untuk menambah jawaban Volker, jika Anda juga ingin mengatur batas waktu baca / tulis selain batas waktu koneksi, Anda dapat melakukan sesuatu seperti berikut ini

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

Kode ini diuji dan berfungsi dalam produksi. Inti lengkap dengan tes tersedia di sini https://gist.github.com/dmichael/5710968

Sadarilah bahwa Anda perlu membuat klien baru untuk setiap permintaan karena conn.SetDeadline yang mereferensikan suatu titik di masa depan dari time.Now()


26
2018-06-05 02:33



Cara cepat dan kotor:

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

Ini adalah mutasi global tanpa koordinasi. Namun itu mungkin baik-baik saja untuk pengeja url Anda. Jika tidak, buat instance pribadi 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)
...

Tidak ada yang diuji di atas.


8
2018-06-03 11:36



Anda dapat menggunakan https://github.com/franela/goreq yang menangani waktu tunggu dengan cara yang sederhana dan sederhana.


1
2018-01-21 19:42



Pada akhirnya saya mengakhiri penggunaan fungsi utilitas ini untuk semua permintaan yang membutuhkan waktu habis. Untuk beberapa alasan, kode @sparrovv bertingkah.

// 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
}

0
2017-08-19 19:25