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的工作流程


image


流程#


我们想发送一次Http请求。首先我们需要构造一个Request,Request本质上是对Http协议的描述(因为大家使用的都是Http协议,所以将这个Request发送到HttpServer后,HttpServer能识别并解析它)。



但是RoundTrip他是个定义在RoundTripper接口中的抽象方法,我们看代码肯定是要去看具体的实现嘛

这里可以使用断点调试法:在上面最后一行上打上断点,会进入到他的具体实现中。从图中可以看到具体的实现在roundtrip中。


image


RoundTrip

紧接着我们需要一个conn,这个conn我们通过Transport可以获取到。conn的类型为persistConn。



整理思路:然后看上面代码中获取conn和roundTrip的实现细节。


我们需要一个conn,这个conn可以通过Transport获取到。conn的类型为persistConn。但是不管怎么样,都得先获取出 persistConn,才能进一步完成发送请求再得到服务端到响应。


然后关于这个persistConn结构体其实上面已经提及过了。重新贴在下面



t.getConn(treq, cm)



transport.dialConn#


下面代码中的cm长这样


image



上面的两条goroutine 和 br bw共同完成如下图的流程


image


发送请求#


func (t *Transport) roundTrip(req *Request) (*Response, error) {}


如下: