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