Go HTTP包:为什么我需要在读取后关闭res.Body ?

  • 本文关键字:读取 Body res HTTP Go go
  • 更新时间 :
  • 英文 :


请参阅此处的示例https://pkg.go.dev/net/http#example-Get。

func main() {
res, err := http.Get("http://www.google.com/robots.txt")
if err != nil {
log.Fatal(err)
}
body, err := io.ReadAll(res.Body)
res.Body.Close() // Why!?
if res.StatusCode > 299 {
log.Fatalf("Response failed with status code: %d andnbody: %sn", res.StatusCode, body)
}
if err != nil {
log.Fatal(err)
}
fmt.Printf("%s", body)
}

我的问题是:为什么我需要关闭第7行的res.Body.Close()。我没有打开它。我在"如果我不关闭response.Body会发生什么?"我知道文档是这么说的。

有更好的方法来解决这个问题吗?

我认为这打破了开/闭原则。我认为如果ReadAll打开了蒸汽,它应该关闭它。这些事情在Go中通常是这样做的吗?

客户端Do()docs:

…如果Body没有同时读到EOF并关闭,则客户端底层RoundTripper(通常是Transport)可能无法为后续操作重用到服务器的持久TCP连接"keep-alive"请求。

总之,如果你不遵循这个建议,你就会积累"死亡"。当请求被执行时,程序中的HTTP连接——但永远不会被清理和/或重用。你的程序的性能会随着时间的推移而下降——这取决于生成了多少连接——你可能会耗尽有限的资源,比如处理网络连接的文件描述符。

看看http包中的Get函数,

func Get(url string) (resp *Response, err error) {
return DefaultClient.Get(url)
}

返回一个指向Response的指针,该指针是一个结构体,包含Body

type Response struct {
. 
.
.
Body io.ReadCloser
.
.
}

挖掘io包的源代码,你会发现ReadCloser涉及io。阅读器和io.Writer。看到这个

关闭打开的Reader将终止等待通道,并关闭底层程序。如果打开的通道太多,会阻碍主机操作系统将空闲进程分配给正在运行的程序,这些程序通常被限制为消耗一定数量的进程(可以更改为吞噬整个进程)。

你所有问题的答案基本上是:因为文档是这么说的。这就是文档的好处所在。有些事情可能是"显而易见的"。对你,有些不是。这就是为什么你要阅读文档并遵循它。

相关内容

  • 没有找到相关文章

最新更新