web-dev-qa-db-fra.com

Comment définir le délai d'expiration pour les requêtes http.Get () dans Golang?

Je crée un récupérateur d'URL dans Go et une liste des URL à récupérer. J'envoie des requêtes http.Get() à chaque URL et j'obtiens leur réponse.

resp,fetch_err := http.Get(url)

Comment définir un délai d'expiration personnalisé pour chaque demande Get? (Le temps par défaut est très long et mon récupérateur est très lent.) Je souhaite que le récupérateur ait un délai d'attente d'environ 40 à 45 secondes après lequel il doit renvoyer "requête expirée" et passer à l'URL suivante.

Comment puis-je atteindre cet objectif?

89
pymd

Apparemment, dans Go 1.3 http.Client a un champ Timeout

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

Cela a fait le tour pour moi.

230
sparrovv

Vous devez configurer votre propre Client avec votre propre Transport qui utilise une fonction de numérotation personnalisée qui enveloppe DialTimeout .

Quelque chose comme (complètement non testé ) 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

Pour ajouter à la réponse de Volker, si vous souhaitez également définir le délai de lecture/écriture en plus du délai de connexion, vous pouvez procéder comme suit:

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

Ce code est testé et fonctionne en production. Le Gist complet avec les tests est disponible ici https://Gist.github.com/dmichael/5710968

Sachez que vous devrez créer un nouveau client pour chaque demande en raison du conn.SetDeadline Qui fait référence à un point futur de time.Now().

29
dmichael

Si vous voulez le faire par requête, la gestion des erreurs est ignorée par souci de concision:

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

Un moyen rapide et sale:

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

C’est un état mondial en mutation, sans aucune coordination. Pourtant, cela pourrait peut-être bien se passer pour votre récupérateur d’URL. Sinon, créez une instance privée de 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)
...

Rien ci-dessus n'a été testé.

8
zzzz

Vous pouvez utiliser https://github.com/franela/goreq , qui gère les délais d'attente de manière simple et simple.

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

Cela peut aider, mais notez que ResponseHeaderTimeout ne commence que lorsque la connexion est établie.

0
T.Max