通过分析gin、beego源码,读懂web框架对http请求处理流程的本质
发布时间:阅读数:115
在实际工作中,大家一定会用到go的web框架。那么,你知道各框架是如何处理http请求的吗?今天就主流的web框架gin
、beego
框架以及go标准库net/http
来总结一下http请求的流程。
一、标准库 net/http 的请求处理流程
首先,我们来看下http包是如何处理请求的。通过以下代码我们就能启动一个http服务,并处理请求:
import ( "net/http")func main() { // 指定路由 http.Handle("/home", &HomeHandler{}) // 启动http服务 http.ListenAndServe(":8000", nil)}type HomeHandler struct {}// 实现ServeHTTPfunc (h *HomeHandler) ServeHTTP(response http.ResponseWriter, request *http.Request) { response.Write([]byte("Hello World"))}
当我们输入http://localhost:8000/home
的时候,就会执行到HomeHandler
的ServeHTTP
方法,并返回Hello World
。
那这里为什么要给HomeHandler
定义ServeHTTP
方法,或者说为什么会执行到ServeHTTP
方法中呢?
我们顺着http.ListenAndServe
方法的定义:
func ListenAndServe(addr string, handler Handler) error
发现第二个参数是个Handler
类型,而Handler
是一个定义了ServeHTTP
方法的接口类型:
type Handler interface { ServeHTTP(ResponseWriter, *Request)}
似乎有了一点点关联,HomeHandler
类型也实现了ServeHTTP
方法。但我们在main函数中调用http.ListenAndServe(":8000", nil)
的时候第二个参数传递的是nil
,那HomeHandler
里的ServeHTTP
方法又是如何被找到的呢?
我们接着再顺着源码一层一层的找下去可以发现,在/src/net/http/server.go
的第1930行有这么一段代码:
serverHandler{c.server}.ServeHTTP(w, w.req)
有个serverHandler
结构体,包装了c.server
。这里的c
是建立的http连接,而c.server
就是在http.ListenAndServe(":8000", nil)
函数中创建的server
对象:
func ListenAndServe(addr string, handler Handler) error { server := &Server{Addr: addr, Handler: handler} return server.ListenAndServe()}
server
中的Handler
就是http.ListenAndServe(":8000", nil)
传递进来的nil
。
好,我们进入 serverHandler{c.server}.ServeHTTP(w, w.req)
函数中再次查看,就可以发现如下代码:
func (sh serverHandler) ServeHTTP(rw ResponseWriter, req *Request) { handler := sh.srv.Handler if handler == nil { handler = DefaultServeMux } ... handler.ServeHTTP(rw, req)}
/src/net/http/server.go
的第2859行到2862行,就是获取到server
中的Handler
,如果是nil
,则使用默认的DefaultServeMux
,然后调用了hander.ServeHTTP
方法。
继续再看DefaultServeMux
中的ServeHTTP
方法,在/src/net/http/server.go
中的第2416行,发现有一行h, _ := mux.Handler(r)
和h.ServeHTTP
方法的调用。这就是通过请求的路径查找到对应的handler
,然后调用该handler
的ServeHTTP
方法。在开始的实例中,就是我们的HomeHandler
的ServeHTTP
方法。
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)}
也就是说ServeHTTP
方法是net/http
包中规定好了要调用的,所以每一个页面处理函数都必须实现ServeHTTP方法。
总结
通过以上两个流行的开源框架gin和beego以及go标准包net/http处理http请求的分析,可以得知所有的web框架启动http服务和处理http的流程都是基于go标准包net/http执行的。 其本质流程都都是通过net/http启动服务,然后调用handler中的ServeHTTP方法。而框架只要实现了http.Handler接口中的ServeHTTP方法,并作为http服务的默认入口,就可以在框架中的ServeHTTP方法中进行路由分发了。如下图: