通过分析gin、beego源码,读懂web框架对http请求处理流程的本质

发布时间:阅读数:547


在实际工作中,大家一定会用到go的web框架。那么,你知道各框架是如何处理http请求的吗?今天就主流的web框架ginbeego框架以及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的时候,就会执行到HomeHandlerServeHTTP方法,并返回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,然后调用该handlerServeHTTP方法。在开始的实例中,就是我们的HomeHandlerServeHTTP方法。

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方法中进行路由分发了。如下图:


原文链接: https://mp.weixin.qq.com/s/rTHNmhBPoL0lTVJsLmU8SA


置顶文章
推荐文章