Adakah `json.NewDecoder().Decode()` Mengabaikan Tarikh Akhir Konteks dalam Permintaan HTTP Go?

Mary-Kate Olsen
Lepaskan: 2024-10-29 04:41:29
asal
594 orang telah melayarinya

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

Go json.NewDecoder().Decode() Abaikan Tarikh Akhir Konteks?

Masalah:

Dalam program Go dengan tarikh akhir konteks, membaca badan respons menggunakan ioutil.ReadAll() menyebabkan tarikh akhir yang dijangkakan melebihi ralat. Walau bagaimanapun, menggunakan json.NewDecoder(resp.Body).Decode() mengembalikan sifar.

Contoh Kod:

<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>
Salin selepas log masuk

Jawapan:

Dalam pakej net/http, penimbal boleh digunakan untuk memproses permintaan. Akibatnya, badan respons masuk mungkin dibaca sebahagian atau keseluruhannya dan ditimbal sebelum percubaan anda untuk membacanya. Akibatnya, konteks yang tamat tempoh mungkin tidak menghalang anda daripada melengkapkan bacaan kandungan. Inilah yang sebenarnya berlaku dalam situasi ini.

Untuk lebih memahami, mari kita ubah kod untuk mencipta pelayan HTTP ujian yang sengaja menangguhkan respons:

<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>
Salin selepas log masuk

Contoh yang diubah suai menghantar JSON objek serupa dengan tindak balas ip.jsontest.com, tetapi menghantar hanya 10 bait pertama badan sebelum mengepamnya. Ia kemudiannya menangguhkan penghantaran selama 6 saat, memberi peluang kepada pelanggan untuk tamat masa.

Apabila kami melaksanakan readDoesntFail(), kami melihat tingkah laku berikut:

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
Salin selepas log masuk

Dalam senario ini, json.Decoder.Decode() cuba membaca daripada sambungan kerana data belum ditimbal lagi. Setelah konteks tamat tempoh, bacaan lanjut daripada sambungan menyebabkan tarikh akhir melebihi ralat. Walau bagaimanapun, dalam contoh asal, json.Decoder.Decode() sedang membaca data yang sudah ditimbal, menjadikan konteks tamat tempoh tidak relevan.

Atas ialah kandungan terperinci Adakah `json.NewDecoder().Decode()` Mengabaikan Tarikh Akhir Konteks dalam Permintaan HTTP Go?. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

sumber:php.cn
Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Artikel terbaru oleh pengarang
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan
Tentang kita Penafian Sitemap
Laman web PHP Cina:Latihan PHP dalam talian kebajikan awam,Bantu pelajar PHP berkembang dengan cepat!