首页  >  文章  >  后端开发  >  为什么当 `ioutil.ReadAll()` 在 Go 的上下文截止日期内返回时,`json.NewDecoder().Decode()` 不返回上下文截止日期错误?

为什么当 `ioutil.ReadAll()` 在 Go 的上下文截止日期内返回时,`json.NewDecoder().Decode()` 不返回上下文截止日期错误?

Barbara Streisand
Barbara Streisand原创
2024-10-31 12:34:31463浏览

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

上下文截止日期内 json.NewDecoder().Decode() 的意外行为

在设置了上下文截止日期的 Go 程序中,响应ioutil.ReadAll() 读取的正文预计会返回错误 (context.DeadlineExceeded)。然而,当使用 json.NewDecoder(resp.Body).Decode() 读取响应正文时,不会观察到这种行为,它返回 nil。

让我们更深入地研究这个问题:

根据响应,net/http 包可能会使用缓冲区来处理请求。这意味着传入的响应正文可以在您执行此操作之前部分或全部读取和缓冲。因此,过期的上下文可能不会阻止您完成正文读取。

为了更清楚地说明这一点,我们调整了一个示例来启动故意部分延迟响应的测试 HTTP 服务器:

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

此测试服务器输出一个类似于 ip.jsontest.com 响应的 JSON 对象。与此相反,它最初只传递 10 个正文字节,然后刷新它们,并在传输剩余部分之前故意休眠 6 秒,为客户端提供过期时间。

当我们使用此服务器执行 readDoesntFail() 时,我们得到:

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

现在,在我们更新的示例中, json.Decoder.Decode() 会努力从连接中读取,因为信息尚未缓冲,允许上下文过期提示由于上下文过期而发生错误。

以上是为什么当 `ioutil.ReadAll()` 在 Go 的上下文截止日期内返回时,`json.NewDecoder().Decode()` 不返回上下文截止日期错误?的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn