深入理解Golang之http server的实现

2020-01-28 14:26:07王旭

ServeMux

Golang中的路由(即 Multiplexer )基于 ServeMux 结构,先看一下 ServeMux 的定义:


type ServeMux struct {
 mu sync.RWMutex
 m  map[string]muxEntry
 es []muxEntry // slice of entries sorted from longest to shortest.
 hosts bool  // whether any patterns contain hostnames
}

type muxEntry struct {
 h  Handler
 pattern string
}

这里重点关注 ServeMux 中的字段 m ,这是一个 mapkey 是路由表达式, value 是一个 muxEntry 结构, muxEntry 结构体存储了对应的路由表达式和 handler

值得注意的是, ServeMux 也实现了 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)
}

也就是说 ServeMux 结构体也是 Handler 对象,只不过 ServeMuxServeHTTP 方法不是用来处理具体的 request 和构建 response ,而是用来确定路由注册的 handler

注册路由

搞明白 HandlerServeMux 之后,我们再回到之前的代码:


DefaultServeMux.Handle(pattern, handler)

这里的 DefaultServeMux 表示一个默认的 Multiplexer ,当我们没有创建自定义的 Multiplexer ,则会自动使用一个默认的 Multiplexer

然后再看一下 ServeMuxHandle 方法具体做了什么:


func (mux *ServeMux) Handle(pattern string, handler Handler) {
 mux.mu.Lock()
 defer mux.mu.Unlock()

 if pattern == "" {
  panic("http: invalid pattern")
 }
 if handler == nil {
  panic("http: nil handler")
 }
 if _, exist := mux.m[pattern]; exist {
  panic("http: multiple registrations for " + pattern)
 }

 if mux.m == nil {
  mux.m = make(map[string]muxEntry)
 }
 // 利用当前的路由和handler创建muxEntry对象
 e := muxEntry{h: handler, pattern: pattern}
 // 向ServeMux的map[string]muxEntry增加新的路由匹配规则
 mux.m[pattern] = e
 // 如果路由表达式以'/'结尾,则将对应的muxEntry对象加入到[]muxEntry中,按照路由表达式长度排序
 if pattern[len(pattern)-1] == '/' {
  mux.es = appendSorted(mux.es, e)
 }

 if pattern[0] != '/' {
  mux.hosts = true
 }
}

Handle 方法主要做了两件事情:一个就是向 ServeMuxmap[string]muxEntry 增加给定的路由匹配规则;然后如果路由表达式以 '/' 结尾,则将对应的 muxEntry