Maison  >  Article  >  développement back-end  >  Pourquoi `json.NewDecoder().Decode()` ne renvoie-t-il pas d'erreur de délai de contexte lorsque `ioutil.ReadAll()` le fait dans un délai de contexte dans Go ?

Pourquoi `json.NewDecoder().Decode()` ne renvoie-t-il pas d'erreur de délai de contexte lorsque `ioutil.ReadAll()` le fait dans un délai de contexte dans Go ?

Barbara Streisand
Barbara Streisandoriginal
2024-10-31 12:34:31463parcourir

Why does `json.NewDecoder().Decode()` not return a context deadline error when `ioutil.ReadAll()` does within a context deadline in Go?

Comportement inattendu de json.NewDecoder().Decode() dans le délai contextuel

Dans les programmes Go avec un délai contextuel défini, la réponse le corps lu par ioutil.ReadAll() devrait renvoyer une erreur (context.DeadlineExceeded). Cependant, ce comportement n'est pas observé lors de la lecture du corps de la réponse avec json.NewDecoder(resp.Body).Decode(), qui renvoie nil.

Approfondissons le problème :

Selon les réponses, le package net/http peut utiliser des tampons pour traiter les requêtes. Cela implique que le corps de la réponse entrante peut être partiellement ou entièrement lu et mis en mémoire tampon avant que vous ne le fassiez. Par conséquent, un contexte expirant peut ne pas vous empêcher de terminer la lecture du corps.

Pour illustrer cela plus clairement, nous avons ajusté un exemple pour lancer un serveur HTTP de test qui retarde délibérément partiellement la réponse :

<code class="go">ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    s := []byte(`{&quot;ip&quot;:&quot;12.34.56.78&quot;}`)
    w.Write(s[:10])
    if f, ok := w.(http.Flusher); ok {
        f.Flush()
    }
    time.Sleep(time.Second * 6)
    w.Write(s[10:])
}))
defer ts.Close()
url = ts.URL

readDoesntFail()
readFails()</code>

Ce serveur de test génère un objet JSON ressemblant à la réponse de ip.jsontest.com. Contrairement à cela, il ne fournit initialement que 10 octets de corps, puis les vide et se met en veille intentionnellement pendant 6 secondes avant de transmettre le reste, donnant au client le temps d'expirer.

Lorsque nous exécutons readDoesntFail() avec ce serveur , nous obtenons :

before reading response body, context error is: context deadline exceeded
panic: Get &quot;http://127.0.0.1:38230&quot;: context deadline exceeded

goroutine 1 [running]:
main.readDoesntFail()
    /tmp/sandbox721114198/prog.go:46 +0x2b4
main.main()
    /tmp/sandbox721114198/prog.go:28 +0x93

Maintenant, avec notre exemple mis à jour, json.Decoder.Decode() fait un effort pour lire à partir de la connexion car les informations ne sont pas encore mises en mémoire tampon, permettant à l'expiration du contexte de provoquer un erreur due à un contexte expiré.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn