go - resp.Body 的内容存储在哪里?
问题描述
我今天做了一个简单的 url 检索器。
1 resp, _ := http.Get("http://www.yahoo.com")
2 text, _ := ioutil.ReadAll(resp.Body)
3 resp.Body.Close()
4 fmt.Printf("%s", text)
结果按预期打印出来。但是,我不明白它为什么起作用。
我对第 2 行的理解ioutil.ReadAll(resp.Body)
返回 []bytes 馈送到“文本”变量。
但:
- resp 是一个 *http.Response 结构
- resp.Body 是一个 io.ReadCloser 接口
- io.ReadCloser 实现 io.Reader 和 io.Closer 接口
- io.Reader 签名为 (p []byte) (n int, err error)
那么,这些 resp.Body 的内容存储在哪里?(与我目前接受 Body 的内容“神奇地”来自某个地方相反)
解决方案
正如@Eklayvya 在评论中提到的,响应正文是按需流式传输的。但是要添加更多上下文。当你打电话时http.Get()
。包中的Get()
函数http/client
初始化一个http.DefaultClient
代表您使用默认 HTTP 标头和元数据创建请求的函数。
实际上,查看源代码会发现,Get
它只是对http.NewRequest()
创建新 HTTP 请求的更常见函数的封装。该请求是由一个底层调用创建的,该调用http.Do(req *Request)
接收请求,执行额外的格式化,然后将请求发送到相关服务器。
有关更多详细信息,文件中有一个func send(ireq *Request, rt RoundTripper, deadline time.Time)
实际http/client.go
执行 http 请求。如果您从函数签名中注意到,它会使用您的请求和名为 a 的第二个参数RoundTripper
。这是事情变得更有趣的地方。
// https://golang.org/src/net/http/client.go (line 117)
// RoundTripper is an interface representing the ability to execute a
// single HTTP transaction, obtaining the Response for a given Request.
//
// A RoundTripper must be safe for concurrent use by multiple
// goroutines.
type RoundTripper interface {
...
RoundTrip(*Request) (*Response, error)
}
RoundTrip
接受 aRequest
并返回Response
包含主体的 a。这是网络传输字节的地方,response.Body
因此您可以[]byte
从网络接收字节。接口的实现RoundTripper
由调用者的要求决定。在这种情况下,它是http.DefaultClient
. 但是,您可以覆盖它并使用它做您想做的事情。
一些网络库确实实现了这个接口。一个例子是包中的ClientConn
结构golang.org/x/net/http2
。第 970 行包含 a 的实现,RoundTrip
其中的主体被写入其中。实现非常复杂,因为它满足并发性,以及超时和其他网络考虑。有兴趣的可以看看。
这是斑点
推荐阅读
- maven - 生成 *.pom 文件到目标目录
- bash - 如何让 curl 等待响应然后继续执行代码
- ios - 如何为基于自动工具的项目启用 Xcode 特定的构建标志
- python-3.x - 当将相同的数组写入此文件时,从 .bin 文件读取的 NumPy 数组的维度不同
- javascript - Adobe Illustrator Extendscript - 使用自定义页面大小打印到特定打印机
- leakcanary - 我找不到泄漏,我的项目 rootview 已删除
- java - 防止 WebLogic 服务器上的 XSD 的外部引用
- sql-server - 我们可以在函数内部使用截断函数吗?
- docker - 如何记录 Docker 容器的内存使用峰值?
- reactjs - 将 Intro.js 与 React Hooks 集成