HTTP请求,JSON,重用连接

huangapple go评论85阅读模式
英文:

HTTP Requests, JSON, reusing connections

问题

我正在使用Go语言通过HTTPS进行多个请求,但是我遇到了不重用连接和端口耗尽的问题。我所做的请求是向一个返回JSON格式数据的API发送请求,然后我使用json.Decode将其解码为Go值。

根据我在这个网站上找到的问题(#1#2),为了让Go语言重用连接进行另一个请求,我必须在关闭连接之前读取完整的响应体(请注意,这并不总是这种行为,如这里所述)。

以前,HTTP客户端的(*Response).Body.Close会尝试持续读取直到EOF,以便重用keep-alive的HTTP连接...

在典型的情况下,我会像之前链接中显示的示例那样使用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)

我不确定这两种方法如何交互。

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

英文:

I'm using Go to make many requests over HTTPS, and I'm having issues with not reusing connections, and running out of ports. The requests I'm making are to an API that returns data in the JSON format, which I then json.Decode into a Go value.

According to questions I've come across on this site (#1, #2), in order for Go to reuse the connection for another request, I must read the entirety of the response's body before closing (note this wasn't always the behavior, as stated here).

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

In a typical instance, I would use the example shown in the earlier links, like so:

ioutil.ReadAll(resp.Body)

but since I'm pulling the data out of the JSON through code like this:

...

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)

I'm not sure how the two methods would interact.

So the question is, how do I make sure the entire response has been read, so that the connection can later be reused for another request?

答案1

得分: 6

如果你只想使用解码器解码单个对象,那么你可以使用More()方法来查看流中是否还有需要读取的内容。

decoder := json.NewDecoder(resp.Body)
err := decoder.Decode(data)
if err != nil {
    // 处理错误
}
if decoder.More() {
    // 流中还有更多数据,所以丢弃剩下的内容
    io.Copy(ioutil.Discard, resp.Body)
}

你也可以在每次调用时使用defer来进行复制,但是这样你可以更容易地处理或记录是否有意外数据或错误。

英文:

If you want to only decode a single object using the Decoder, then you can use the More() method to see if there is more in the stream that needs to be read.

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

You can also just defer the Copy on every call, but this way you could more easily handle or log if there was unexpected data or an error.

huangapple
  • 本文由 发表于 2015年10月20日 14:51:20
  • 转载请务必保留本文链接:https://go.coder-hub.com/33229860.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定