Golang net/http流程
简单的http server
1 | func myHandlerFunc(w http.ResponseWriter, r *http.Request){ |
注意到注册路由的两种方式,即http.HandleFunc
和http.Handle
非成员方法会默认以DefaultServeMux
为receiver,可见这两种方式最终都会调用DefaultServeMux.Handle
.
1 | // server.go |
ServeMux
ServeMux
是HTTP
request的multiplexer.所谓multiplexer,就是Server会处理对于多个不同url的请求,应该根据最长url匹配的原则把请求转发给指定的handler.DefaultServeMux
是一个ServerMux
的实例,在上例中调用全局的Handle
HandleFunc
等函数时,实际是在配置DefaultServeMux
。监听时ListenAndServe
的第二个参数留空,同样也是默认使用DefaultServeMux
.
1 | type ServeMux struct { |
ServerMux
中的mu
字段维护了一个从pattern(路由表达式)到muxEntry
的映射。muxEntry
简单的把路由表达式和handler组合在一起。
Handler
Handler是一个接口,只有一个方法ServeHTTP()
.一个Handler
(以及它的唯一方法)的职责是处理Request并构建Response.这也是golang的http服务暴露给开发者的入口,许多web框架自定义实现了Handler
.
值得注意的是,ServeMux
也实现了Handler
接口,它将请求转发给最匹配的url所对应的handler。也就是说,我们可以使用ServeMux
对象或者干脆使用DefaultServeMux
来作为Handler
.
1 | type Handler interface { |
小Tip
回到一开始ServeMux
的HandleFunc
成员函数:
1 | func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) { |
注意第5行的HandlerFunc(handler)
,它的作用是把一个具有func(Response Writer, *Request)
签名的函数转变为实现了Handler
接口的对象。
1 | // The HandlerFunc type is an adapter to allow the use of |
通过一层wrapper优雅地实现了这一点,上述的HandlerFunc(handler)
不是函数调用,而是一个类型转换。
回到DefaultServeMux.Handle
1 | func (mux *ServeMux) Handle(pattern string, handler Handler) { |
这个函数主要做了以下工作:
- 建立从url模式到对应handler的映射。
- 如果模式以'/'结尾,对应一个子树中所有的url,把它加入es列表中,按照最长有限匹配的原则从长到短排序。
- 不以'/'开头的模式表示只匹配某个主机名下的URL.
ListenAndServe
http
的ListenAndSere
方法创建了一个Server
对象并调用了其同名方法。Server
的ListenAndServe
会初始化监听地址,调用Listen
方法设置监听,把Listen
返回的监听器对象传入Serve
方法。Serve
方法对每一个连接创建conn
即连接对象,每个连接对象调用自己的serve
方法,该方法中实际处理请求的语句是serverHandler{c.server}.ServeHTTP(w, w.req)
.
1 | // serverHandler delegates to either the server's Handler or |
serverHandler
开启了一系列调用流程,并最终调用了用户在ListenAndServe
中指定的handler
,如果为nil
则会使用DefaultServeMux
.
Best Practice
我们可以看出,为了把url模式绑定到指定的handler,我们有多种方式:
直接使用
http.HandleFunc
绑定,ListenAndServe
时使用nil
作为handler
.这是使用了默认的DefaultServeMux
.使用
HandlerFunc
(注意之前提及的,这是一个强制类型转换的adaptor)把一个函数转化为Handler
对象并用于ListenAndServe
.1
2
3
4
5
6func foo(w http.ResponseWriter, r *http.Request){
//balabala
}
handler := http.HandlerFunc(foo)
http.ListenAndServe(":9090",handler)创建一个自定义的
ServeMux
,在里面注册handler.1
2
3
4mux := http.NewServeMux()
mux.HandleFunc("/one", HandlerOne)
mux.HandleFunc("/two", HandlerTwo)
http.ListenAndServe(":8001", mux)
建议使用第三种方式。
参考资料
- https://juejin.cn/post/6844903998869209095