nethttp server source

golang net/http Server主要流程源码分析。

时间:2019年3月14日

处理一个http请求大致思路如下:

  • 创建一个net.Listener对象

  • net.Listener对象Accept一个tcp连接

  • 从tcp连接读取一个请求并创建一个响应体

  • 调用接口处理这个连接的请求并写入数据udao响应

主要堆栈:

http.ListenAndServe(addr string, handler Handler) error

    http.*Server.ListenAndServe() error

        net.Listen(network, address string) (net.Listener, error)

        http.*Server.Serve(l net.Listener) error

            http.*Server.setupHTTP2_Serve()

            net.Listener.Accept() (net.Conn, error)

            http.*Server.newConn(rwc net.Conn) *http.conn

            http.*conn.setState(nc net.Conn, state ConnState)

            http.*conn.serve(ctx context.Context)

                defer http.*conn.serve.func()

                http.*conn.rwc.(*tls.Conn)

                    tls.*Conn.Handshake()

                    tls.ConnectionState.NegotiatedProtocol

                http.*conn.readRequest(ctx context.Context) (w *http.response, err error)

                http.serverHandler{http.*conn.server}.ServeHTTP(w, w.req)

Start

启动一个Server

http.ListenAndServe

首先http.ListenAndServe会创建一个Server,设置地址和Handler,然后调用Server对象的ListenAndServe方法启动。

ListenAndServe方法先检查srv的状态是否是关闭,服务是关闭的就直接退出

然后设置默认地址,利用地址监听tcp连接,最后调用Server对象的Serve的方法,处理这个监听。

Serve

Server对象的Serve方法才是处理个监听的主要过程,启动顺序函数如下:

testHookServerServe执行net/http库默认的测试函数。

onceCloseListener对象封装net.Listener对象的Close方法,使用sync.Once对象确保net.Listener只会关闭一次。

setupHTTP2_Serve设置http2,如果启用了https默认就是http2,h2可以使用环境变量设置是否启动,具体不分析。

trackListener设置track日志,忽略。

baseCtx是Server一个监听的根Context。

for循环处理Accept到的连接。

如果Accept返回err,会srv.getDoneChan()方法检测Server是否结束,后序忽略。

Accept获得了一个net.Conn连接对象,使用srv.newConn方法创建一个http.conn连接。

http.conn连接就是http连接,设置连接状态用于连接复用,然后c.serve处理这个http连接。

http.Server.Serve完整源码如下:

net.conn.serve

net.conn.serve处理一个http连接。

WithValue设置Context,忽略。

defer部分捕捉panic抛出的错误,然后Server对象输出,如果Server对象设置了log.Logger,就输出到log,否则输出到默认。

defer后部分,检测http连接的状态,非劫持状态就关闭连接,设置http状态成关闭;劫持状态一般在Websock下,使用Hijack方法获取了tcp连接,然后自定义处理。

c.rwc就是net.Conn的连接,net.Conn实现了Reader、Writer、Closer接口,所以缩写rwc。

rwc连接断言判断是否是tls.Conn连接,判断是否是https连接;如果是就设置rwc的超时,

tlsConn.Handshake()是检测tls握手是否正常,不正常就返回http 400的响应并关闭连接;

获取NegotiatedProtocol信息,就是NextProto的值,如果值是h2,就使用h2的连接处理;h2详细见h2握手分析,此tls部分可忽略,是tls的ALPN扩展的支持。

注意:tlsConn.Handshake()一定要执行,是验证tls握手,然后才会有NegotiatedProtocol等tls连接信息。

注意:NegotiatedProtocol是tls的ALPN扩展的关键,h2协议握手下的值就是h2

tls部分完整如下:

tls部分没将请求变成h2就继续按http/1.1处理请求。

newBufioReader部分对rwc,使用bufio变成缓冲读写。

然后for循环调用net.conn.readRequest读取一个请求,并创建ResponseWriter对象。

如果读取请求错误,就直接返回4xx错误响应并关闭连接。

创建一个serverHandler处理当前的请求rw,serverHandler就检测Server是否设置了默认处理者,和响应Option方法,可忽略。

然后判断连接状态是否劫持,劫持直接结束。

...

注意:serverHandler{c.server}.ServeHTTP(w, w.req),就是用连接先创建request和response对象,然使用http.Handler对象来处理这个请求。

http.serverHandler定义:

...

net.conn.serve完整定义如下:

net.conn.readRequest

readRequest方法就是根据连接创建http.Request和http.ResponseWriter两个对象供http.Handler接口使用,处理一个请求。

end

创建一个Server并处理http请求到此就结束。

http.HandleFunc

http.HandleFunc使用http.DefaultServeMux这个默认路由调用HandleFunc方法注册一个路由。

http.Handler

http.Handler是net/http库处理请求的接口,http.Server直接调用Handler处理请求。

http.ServeMux是net/http库内置的路由器,执行了基本匹配,但是实现了http.Handler接口,Server就直接使用Mux。

HandlerFunc是处理函数,但是这个类型实现了http.Handler接口,就将一个函数转换成了接口。

一下两种方法都将func(ResponseWriter, *Request){}这样一个函数转换成了http.Handler接口

Middleware

基于net/http简单实现中间件,使用http.Handler接口,使用装饰器模式嵌套一层。

Logger对象实现了http.Handler接口,会先输出请求信息,然后调用路由处理这个请求。

http.ServeMux是标准库实现的路由器,会匹配并处理请求。

Last updated