之前说了几种golang中设置http server的方式,这里接着记录一下阅读源码时看到的一个server是如何处理用户请求的,还是从server的启动开始看起。
step 1:
初始化一个Server结构体实例后, 执行Server.ListenAndServer函数(其中主要调用net.Listen 和 Server.Serve函数)
step 2:
接着进入Server.Serve部分的代码,看看详细的处理过程,可以看到主要是在主goroutine中用for循环阻塞,不断通过Accept函数接收读取连接请求,然后调用Server.newConn()函数,创建一个连接实例c,然后每个连接实例启动一个新的goroutine去执行处理,从这里也能看出, 如果并发请求很高的时候,会创建出海量的goroutine来并发处理请求。
这一步,调用newConn函数,会创建一个conn结构体的示例客户端,其中的server成员变量是Server实例,即每个connection示例都保留了指向server的信息。
step 3:
接着我们进入每个connection处理的goroutine,看具体做了什么工作,这个函数有一百多行这里就不完整摘了,看看其主要的代码部分:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19func (c *conn) serve(ctx context.Context) {
for{
...
w, err := c.readRequest(ctx)
...
req := w.req
...
// HTTP cannot have multiple simultaneous active requests.[*]
// Until the server replies to this request, it can't read another,
// so we might as well run the handler in this goroutine.
// [*] Not strictly true: HTTP pipelining. We could let them all process
// in parallel even if their responses need to be serialized.
// But we're not going to implement HTTP pipelining because it
// was never deployed in the wild and the answer is HTTP/2.
serverHandler{c.server}.ServeHTTP(w, w.req)
w.cancelCtx()
}
}
从上面的代码片段可以看出, 先调用connection的readRequest函数构造一个response对象, 然后执行serverHandler{c.server}.ServeHTTP(w, w.req)进行实际的请求处理,后面我们来看看这个请求的过程。
step4:
先看看serverHandler的定义,可以看到其是一个结构体,有一个成员属性srv,结合step 3可以看出,serverHandler{c.server}.ServeHTTP(w, w.req)就是实例化了一个serverHandler结构体,然后执行其成员函数ServeHTTP,在ServeHTTP成员函数的定义中,可以看到,主要是调用了初始化server时的Handler成员属性,然后执行handler.ServeHTTP(rw, req)进行调用。
1 | // serverHandler delegates to either the server's Handler or |
对于如下的例子,其实就是在调用aa.ServeHTTP(),因为此时的server.Handler就是aa这个结构体的实例。1
2
3
4
5
6
7
8
9type aa struct {
}
func (a aa) ServeHTTP(res http.ResponseWriter, req *http.Request) {
res.Write([]byte("hhhhhh"))
}
func main() {
http.ListenAndServe(":8080", aa{})
}
对于使用serveMux的例子,这里的server.Handler就是如下serveMux的实例,这中方式下,用户自定义的处理函数都被类型转化为一个HandlerFunc类型,HandlerFunc同样实现了Handler接口
1 | // test3 我们可以增加一个ServeMux来做一个请求路由处理工作 |
serveMux结构体定义如下,从中可以看出它的ServeHTTP成员函数主要是根据URL pattern取出合适的Handler,这里的每个Handler都是一个HandlerFunc类型, 然后执行h.ServeHTTP(w, r)。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30type ServeMux struct {
mu sync.RWMutex
m map[string]muxEntry
hosts bool // whether any patterns contain hostnames
}
type muxEntry struct {
h Handler
pattern string
}
func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) {
if r.RequestURI == "*" {
if r.ProtoAtLeast(1, 1) {
w.Header().Set("Connection", "close")
}
w.WriteHeader(StatusBadRequest)
return
}
h, _ := mux.Handler(r)
h.ServeHTTP(w, r)
}
type HandlerFunc func(ResponseWriter, *Request)
// ServeHTTP calls f(w, r).
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
f(w, r)
}
.. 待续