http.Response.Body的Read方法内部工作原理是怎样的?
http.Response.Body.Read 方法运行逻辑
这两种说法都不准确,resp.Body.Read的实际运行逻辑是直接和TCP流的接收机制绑定的,具体可以拆解为以下几点:
resp.Body是Go标准库对HTTP响应TCP连接的封装,它本身不会预先一次性拉取全部响应数据存储到用户态内存,只有你主动调用读取方法才会从内核缓冲区拿数据。- 每次调用
Read(buf)时的执行流程:- 先检查内核套接字缓冲区中是否有已经收到但未被读取的响应数据
- 若有数据,最多拷贝
len(buf)个字节到你传入的切片中,不会强制等buf填满才返回:哪怕当前可读取的字节数小于buf的长度,也会直接返回实际读取到的字节数 - 若内核缓冲区无可用数据,调用会陷入阻塞,直到内核收到新的TCP报文、连接断开或者出现IO错误
- 只有当服务端已经发送完全部响应数据,且所有数据都已经被读取完毕后,下一次调用
Read才会返回io.EOF
- 补充几个开发注意点:
- 只要
Read返回的实际读取字节数r>0,哪怕同时返回了错误,也要优先处理buf[:r]的有效数据,不能直接跳过 - 不要假设每次
Read都会把buf填满,所有逻辑都要以返回的r作为有效数据长度的依据 - 读取完
resp.Body必须主动调用Close方法,否则会造成TCP连接泄漏
- 只要
你贴的代码示例有个小缺陷:没有处理返回的有效字节,正确的写法应该是先处理buf[:r]再判断错误:
var resp *http.Response buf := make([]byte, 50) defer resp.Body.Close() // 别忘了关闭Body for { r, err := resp.Body.Read(buf) if r > 0 { // 这里处理buf[:r]的有效数据 } if err == io.EOF { break } if err != nil { // 处理其他IO错误 break } }
内容的提问来源于stack exchange,提问作者akshay khairmode
相关产品推荐
相关产品推荐

