HttpClient源码阅读#
DemoCode#
整理思路#
http.Client的代码其实是很多的,全部很细的过一遍肯定也会难度,下面可能也是只能提及其中的一部分。
首先明白一件事,我们编写的HttpClient是在干什么?(虽然这个问题很傻,但是总得问一下)是在发送Http请求。
一般我们在开发的时候,更多的编写的是HttpServer的代码。是在处理Http请求, 而不是去发送Http请求,Http请求都是是前端通过ajax经由浏览器发送到后端的。
net.Dial("tcp",adds)
那也就是说,我们要看看,http.Client是如何在和服务端建立连接、发送数据、接收数据的。
重要的struct#
http.Client中有机几个比较重要的struct,如下
http.Client结构体中封装了和http请求相关的属性,诸如 cookie,timeout,redirect以及Transport。
Tranport实现了RoundTrpper接口:
RoundTrip
RoundTrpper被设计成了一个支持并发的结构体。
Transport结构体如下:
其中的connectMethodKey也是结构体:
persistConn是一个具体的连接实例,包含连接的上下文。
另外补充一个结构体:Request,他用来描述一次http请求的实例,它定义于http包request.go, 里面封装了对Http请求相关的属性
这几个结构体共同完成如下图所示http.Client的工作流程
流程#
我们想发送一次Http请求。首先我们需要构造一个Request,Request本质上是对Http协议的描述(因为大家使用的都是Http协议,所以将这个Request发送到HttpServer后,HttpServer能识别并解析它)。
但是RoundTrip他是个定义在RoundTripper接口中的抽象方法,我们看代码肯定是要去看具体的实现嘛
这里可以使用断点调试法:在上面最后一行上打上断点,会进入到他的具体实现中。从图中可以看到具体的实现在roundtrip中。
RoundTrip
紧接着我们需要一个conn,这个conn我们通过Transport可以获取到。conn的类型为persistConn。
整理思路:然后看上面代码中获取conn和roundTrip的实现细节。
我们需要一个conn,这个conn可以通过Transport获取到。conn的类型为persistConn。但是不管怎么样,都得先获取出 persistConn,才能进一步完成发送请求再得到服务端到响应。
然后关于这个persistConn结构体其实上面已经提及过了。重新贴在下面
t.getConn(treq, cm)
transport.dialConn#
下面代码中的cm长这样
上面的两条goroutine 和 br bw共同完成如下图的流程
发送请求#
func (t *Transport) roundTrip(req *Request) (*Response, error) {}
如下: