转 [golang]为什么Response.Body需要被关闭
Body io.ReadCloser- The http Client and Transport guarantee that Body is always non-nil, even on
- responses without a body or responses with a zero-length body. It is the caller's
- responsibility to close Body. The default HTTP client's Transport does not attempt to
- reuse HTTP/1.0 or HTTP/1.1 TCP connections ("keep-alive") unless the Body is read to
- completion and is closed.
- http客户端(Client)和传输(Transport)保证响应体总是非空的,即使响应没有响应体或0长响应
- 体。关闭响应体是调用者的责任。默认http客户端传输(Transport)不会尝试复用keep-alive的
- http/1.0、http/1.1连接,除非请求体已被完全读出而且被关闭了。
以上是http包文档说明。但是为什么body需要被关闭呢,不关闭会如何?那就读源码呗。
要了解body,首先要了解http事务是如何处理的。http事务是交由底层的Transport处理的。
第一步是从连接池获取一个连接,这个连接的功能由3个goroutine协同实现,一个主goroutine,一个readLoop,一个writeLoop,后两个goroutine生命周期和连接一致。虽说readLoop和writeLoop名字叫循环(也确实是for循环),但实际上一次循环就完整处理一个http事务,循环本身仅仅是为了连接复用,所以为了便于理解其逻辑可以忽略它的循环结构。
接下来三个goroutine协同完成http事务:
- 主goroutine将request同时发给readLoop和writeLoop。
- writeLoop发送request,然后将状态(error)发送给主goroutine和readLoop。
- readLoop解析头部response,然后将状态(error)和response发送给主goroutine。
- 主goroutine返回用户代码,readLoop等待body读取完成。
- readLoop回收连接。
了解http事务的处理流程,然后我们回过头来看看神秘的body到底是什么
- //源码版本1.8.3
- // src/net/http/transfer.go:405 body解析方法
- func readTransfer(msg interface{}, r *bufio.Reader) (err error)
- // src/net/http/transfer.go:485 解析chunked
- t.Body = &body{src: internal.NewChunkedReader(r), hdr: msg, r: r, closing: t.Close}
- // src/net/http/transfer.go:490 产生eof
- t.Body = &body{src: io.LimitReader(r, realLength), closing: t.Close}
- // src/net/http/transport.go:1560 发送eof信号
- body := &bodyEOFSignal{
- // src/net/http/transport.go:1583 gzip解码
- resp.Body = &gzipReader{body: body}
body实际上是一个嵌套了多层的net.TCPConn:
- bufio.Reader,这层尝试将多次小的读操作替换为一次大的读操作,减少系统调用的次数,提高性能;
- io.LimitedReader,tcp连接在读取完body后不会关闭,继续读会导致阻塞,所以需要LimitedReader在body读完后发出eof终止读取;
- chunkedReader,解析chunked格式编码(如果不是chunked略过);
- bodyEOFSignal,在读到eof,或者是提前关闭body时会对readLoop发出回收连接的通知;
- gzipReader,解析gzip压缩(如果不是gizp压缩略过);
从上面可以看出如果body既没有被完全读取,也没有被关闭,那么这次http事务就没有完成,除非连接因超时终止了,否则相关资源无法被回收。
如果请求头或响应头指明Connection: close呢?还是无法回收,因为close表示在http事务完成后断开连接,而事务尚未完成自然不会断开,更不会回收。
从实现上看只要body被读完,连接就能被回收,只有需要抛弃body时才需要close,似乎不关闭也可以。但那些正常情况能读完的body,即第一种情况,在出现错误时就不会被读完,即转为第二种情况。而分情况处理则增加了维护者的心智负担,所以始终close body是最佳选择。
作者:一桶冷水
链接:https://www.jianshu.com/p/407fada3cc9d
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。
转 [golang]为什么Response.Body需要被关闭的更多相关文章
- golang 网络编程之如何正确关闭tcp连接以及管理它的生命周期
欢迎访问我的个人网站获取更佳阅读排版 golang 网络编程之如何正确关闭tcp连接以及管理它的生命周期 | yoko blog (https://pengrl.com/p/47401/) 本篇文章部 ...
- Golang控制goroutine的启动与关闭
最近在用golang做项目的时候,使用到了goroutine.在golang中启动协程非常方便,只需要加一个go关键字: go myfunc(){ //do something }() 但是对于一些长 ...
- 【GoLang】golang context channel 详解
代码示例: package main import ( "fmt" "time" "golang.org/x/net/context" ) ...
- java.lang.IllegalStateException: getWriter() has already been called for this response问题解决
java.lang.IllegalStateException: getWriter() has already been called for this response问题解决 java.lang ...
- JSP最常用的五种内置对象(out,request,response,session,application)
为了简化开发过程,JSP提供了一些内置对象,它们由容器实现和管理.开发者在JSP页面中无需声明,无需实例化就可使用.主要有out,request,response,session,applicatio ...
- OkHttp踩坑记:为何 response.body().string() 只能调用一次?
想必大家都用过或接触过 OkHttp,我最近在使用 Okhttp 时,就踩到一个坑,在这儿分享出来,以后大家遇到类似问题时就可以绕过去. 只是解决问题是不够的,本文将 侧重从源码角度分析下问题的根本, ...
- C# Response 下载
//TransmitFile实现下载 protected void Button1_Click(object sender, EventArgs e) { /* 微软为Response对象提供了一个新 ...
- gprc-java与golang分别实现服务端,客户端,跨语言通信(二.golang实现)
1.编译器protoc, 下载地址:https://github.com/protocolbuffers/protobuf/releases (下载对应的版本, 解压后放到go的bin中) 2.安装 ...
- 如何保障Go语言基础代码质量?
为什么要谈这个topic? 实践中,质量保障体系的建设,主要针对两个目标: 一是不断提高目标业务测试覆盖率,保障面向客户的产品质量:二就是尽可能的提高人效,增强迭代效率.而构建全链路质量卡点就是整个体 ...
- Netty构建分布式消息队列实现原理浅析
在本人的上一篇博客文章:Netty构建分布式消息队列(AvatarMQ)设计指南之架构篇 中,重点向大家介绍了AvatarMQ主要构成模块以及目前存在的优缺点.最后以一个生产者.消费者传递消息的例子, ...
随机推荐
- Grafana 系列-统一展示-1-开篇
系列文章 Grafana 系列文章 Grafana 简介 Grafana 是 Grafana Labs 的第一款也是最重要的产品.它的定位是可视化, 用于监控展示 和 可观察性. 是当前最为完善.流行 ...
- 家庭实验室系列文章-如何迁移树莓派系统到更大的 SD 卡?
前言 其实这个专题很久很久之前就想写了,但是一直因为各种原因拖着没动笔. 因为没有资格,也没有钱在一线城市买房 (); 但是在要结婚之前,婚房又是刚需. 我和太太最终一起在一线城市周边的某二线城市买了 ...
- Java List集合去重、过滤、分组、获取数据、求最值、合并、排序、跳数据和遍历
前言 请各大网友尊重本人原创知识分享,谨记本人博客:南国以南i. 准备工作:现有一个User类.Student 类和Ticket类,加入相关依赖 @Data public class User { / ...
- AI极速批量换脸!Roop-unleashed下载介绍,可直播
要说AI换脸领域,最开始火的项目就是Roop了,Roop-unleashed作为Roop的嫡系分支,不仅继承了前者的强大基因,更是在功能上实现了重大突破与升级 核心特性 1.可以进行高精度的图片.视频 ...
- 力扣189(java)-轮转数组(中等)
题目: 给你一个数组,将数组中的元素向右轮转 k 个位置,其中 k 是非负数. 示例 1: 输入: nums = [1,2,3,4,5,6,7], k = 3输出: [5,6,7,1,2,3,4]解释 ...
- SpringBoot Admin2.0 集成 Java 诊断神器 Arthas 实践
简介: 项目最初使用 Arthas 主要有两个目的: 1. 通过 arthas 解决实现测试环境.性能测试环境以及生产环境性能问题分析工具的问题. 2. 通过使用 jad.mc.redefine 功能 ...
- 内含干货PPT下载|一站式数据管理DMS及最新解决方案发布
简介: 今天主要给大家介绍一站式数据管理平台DMS以及解决方案的发布.议题包含企业数据管理当前的一些痛,DMS一站式数据管理平台以及其核心技术,实时数仓解决方案以及相应的应用实践. "数聚 ...
- Dubbo3.0|阿里巴巴服务框架三位一体的选择与实践
简介: 服务框架就像铁路的铁轨一样,是互通的基础,只有解决了服务框架的互通,才有可能完成更高层的业务互通,所以用相同的标准统一,合二为一并共建新一代的服务框架是必然趋势.Dubbo3.0 是 Dub ...
- LlamaIndex 起步教程(本地模型)
提示:确保您已先按照自定义安装步骤操作. 这是一个著名的"五行代码"起步示例,使用本地 LLM(大语言模型)和嵌入模型.我们将使用 BAAI/bge-small-en-v1.5 作 ...
- Niginx中Vue Router 历史(history)模式的配置
快速配置 将build后的文件直接丢到niginx目录下的html文件夹中,然后配置nginx.conf,就可以在快速的实现niginxhistory模式的配置了. location /{ # 可使用 ...