HTTP请求、JSON、重用连接

4

我正在使用Go语言通过HTTPS进行多次请求,但是我遇到了不重用连接和端口耗尽的问题。我发起的请求是针对返回JSON格式数据的API,然后我使用json.Decode将其转换为Go值。

根据我在本站上遇到的问题(#1#2),为了使Go重用连接进行另一个请求,我必须在关闭之前读取响应体的全部内容(请注意,这并不总是这种行为,如此处所述)。

Previously the HTTP client's (*Response).Body.Close would try to keep
reading until EOF, hoping to reuse the keep-alive HTTP connection...

在典型情况下,我会像早期链接中展示的示例一样使用它,如下所示:
ioutil.ReadAll(resp.Body)

但是由于我是通过这样的代码从JSON中提取数据的:

...

req, _ := http.NewRequest("GET", urlString, nil)
req.Header.Add("Connection", "keep-alive")
resp, err = client.Do(req)
defer resp.Body.Close()

...

decoder := json.NewDecoder(resp.Body)
decoder.Decode(data)

我不确定这两种方法会如何相互作用。

所以问题是,如何确保整个响应已被读取,以便稍后可以重用连接进行另一个请求?


1
嗯,也许最简单的方法是自己实现旧的行为:defer func() { io.Copy(ioutil.Discard, resp.Body); resp.Body.Close() }() - twotwotwo
也许在 decoder.Decode(data) 返回后,你已经读取了所有数据。 - nvcnvn
1
如果您只期望在主体中收到一个合理大小的JSON响应,请不要使用解码器。使用ReadAll和json.Unmarshal即可。 - JimB
我期望JSON的大小是合理的,但可能会有许多并发/并行的goroutine处理每个响应。目前我在一个具有足够RAM处理此操作的系统上,但我不想依赖它。 - bawjensen
1个回答

6

如果您只想使用解码器解码单个对象,则可以使用More()方法查看是否有更多需要读取的流。

decoder := json.NewDecoder(resp.Body)
err := decoder.Decode(data)
if err != nil {
    // handle err
}
if decoder.More() {
    // there's more data in the stream, so discard whatever is left
    io.Copy(ioutil.Discard, resp.Body)
}

您也可以在每次调用时只延迟复制,但是这种方式可以更轻松地处理或记录是否存在意外数据或错误。


是的,我遇到了 More(),但我不确定它是否完全符合我的需求。谢谢! - bawjensen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接