Ignoriert „json.NewDecoder().Decode()' Kontextfristen in Go-HTTP-Anfragen?

Mary-Kate Olsen
Freigeben: 2024-10-29 04:41:29
Original
680 Leute haben es durchsucht

 Does `json.NewDecoder().Decode()` Ignore Context Deadlines in Go HTTP Requests?

Go json.NewDecoder().Decode() ignoriert Kontextfrist?

Problem:

In einem Go-Programm Bei einer Kontextfrist führt das Lesen eines Antworttexts mit ioutil.ReadAll() zum Fehler „Erwartete Frist überschritten“. Die Verwendung von json.NewDecoder(resp.Body).Decode() gibt jedoch stattdessen Null zurück.

Codebeispiel:

<code class="go">package main

import (
    "context"
    "encoding/json"
    "fmt"
    "io/ioutil"
    "net/http"
    "time"
)

var url string = "http://ip.jsontest.com/"

func main() {
    readDoesntFail()
    readFails()
}

type IpResponse struct {
    Ip string
}

func readDoesntFail() {
    ctx, _ := context.WithTimeout(context.Background(), time.Second*5)

    req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
    if err != nil {
        panic(err)
    }
    resp, err := http.DefaultClient.Do(req)
    if err != nil {
        panic(err)
    }

    ipResponse := new(IpResponse)
    time.Sleep(time.Second * 6)
    fmt.Println("before reading response body, context error is:", ctx.Err())
    err = json.NewDecoder(resp.Body).Decode(ipResponse)
    if err != nil {
        panic(err)
    }
    fmt.Println("Expected panic but there was none")
}

func readFails() {
    ctx, _ := context.WithTimeout(context.Background(), time.Second*5)
    req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
    if err != nil {
        panic(err)
    }
    resp, err := http.DefaultClient.Do(req)
    if err != nil {
        panic(err)
    }

    time.Sleep(time.Second * 6)
    fmt.Println("before reading response body, context error is:", ctx.Err())
    _, err = ioutil.ReadAll(resp.Body)
    if err != nil {
        fmt.Println("received expected error", err)
    }
}</code>
Nach dem Login kopieren

Antwort:

Im net/http-Paket können Puffer zur Verarbeitung von Anfragen verwendet werden. Folglich wird der eingehende Antworttext möglicherweise teilweise oder vollständig gelesen und gepuffert, bevor Sie versuchen, ihn zu lesen. Daher hindert Sie ein ablaufender Kontext möglicherweise nicht daran, die Lektüre des Textes abzuschließen. Genau das passiert in dieser Situation.

Zum besseren Verständnis ändern wir den Code, um einen Test-HTTP-Server zu erstellen, der die Antwort absichtlich verzögert:

<code class="go">ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    s := []byte(`{"ip":"12.34.56.78"}`)
    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>
Nach dem Login kopieren

Das geänderte Beispiel sendet einen JSON Objekt ähnlich der Antwort von ip.jsontest.com, überträgt jedoch nur die ersten 10 Bytes des Körpers, bevor er geleert wird. Anschließend wird die Übertragung für 6 Sekunden unterbrochen, sodass der Client eine Zeitüberschreitung erhält.

Wenn wir readDoesntFail() ausführen, beobachten wir das folgende Verhalten:

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

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

In diesem Szenario json.Decoder.Decode() versucht, aus der Verbindung zu lesen, da die Daten noch nicht gepuffert wurden. Sobald der Kontext abläuft, führen weitere Lesevorgänge aus der Verbindung zu einem Fehler wegen Fristüberschreitung. Im ursprünglichen Beispiel liest json.Decoder.Decode() jedoch bereits gepufferte Daten, wodurch der abgelaufene Kontext irrelevant wird.

Das obige ist der detaillierte Inhalt vonIgnoriert „json.NewDecoder().Decode()' Kontextfristen in Go-HTTP-Anfragen?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Quelle:php.cn
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Neueste Artikel des Autors
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage