Example

  1. package main
  2. import (
  3. "fmt"
  4. "log"
  5. "net/http"
  6. )
  7. func sayHello(w http.ResponseWriter, r *http.Request) {
  8. fmt.Fprintf(w, "Hello World!")
  9. }
  10. func main() {
  11. http.HandleFunc("/", sayHello)
  12. err := http.ListenAndServe(":9090", nil)
  13. if err != nil {
  14. log.Fatal("ListenAndServe: ", err)
  15. }
  16. }

Execute Flow

http.HandleFunc

  1. func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
  2. DefaultServeMux.HandleFunc(pattern, handler)
  3. }
  4. func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
  5. if handler == nil {
  6. panic("http: nil handler")
  7. }
  8. mux.Handle(pattern, HandlerFunc(handler))
  9. }
  10. func (mux *ServeMux) Handle(pattern string, handler Handler) {
  11. mux.mu.Lock()
  12. defer mux.mu.Unlock()
  13. ...
  14. if mux.m == nil {
  15. mux.m = make(map[string]muxEntry)
  16. }
  17. e := muxEntry{h: handler, pattern: pattern}
  18. mux.m[pattern] = e
  19. if pattern[len(pattern)-1] == '/' {
  20. mux.es = appendSorted(mux.es, e)
  21. }
  22. if pattern[0] != '/' {
  23. mux.hosts = true
  24. }
  25. }
  26. func appendSorted(es []muxEntry, e muxEntry) []muxEntry {
  27. n := len(es)
  28. i := sort.Search(n, func(i int) bool {
  29. return len(es[i].pattern) < len(e.pattern)
  30. })
  31. if i == n {
  32. return append(es, e)
  33. }
  34. // we now know that i points at where we want to insert
  35. es = append(es, muxEntry{}) // try to grow the slice in place, any entry works.
  36. copy(es[i+1:], es[i:]) // Move shorter entries down
  37. es[i] = e
  38. return es
  39. }
  1. type ServeMux struct {
  2. mu sync.RWMutex
  3. m map[string]muxEntry
  4. es []muxEntry // slice of entries sorted from longest to shortest.
  5. hosts bool // whether any patterns contain hostnames
  6. }
  7. type muxEntry struct {
  8. h Handler
  9. pattern string
  10. }
  11. var DefaultServeMux = &defaultServeMux
  12. var defaultServeMux ServeMux

按顺序做了几件事:

  1. 调用了 DefaultServerMux 的 HandleFunc
  2. 调用了 DefaultServerMux 的 Handle
  3. 往 DefaultServeMux 的 map[string]muxEntry 中增加对应的 handler 和路由规则

直接调用 HandleFunc ,会间接调用 mux.HandleFunc ,之后 mux.Handle() 将传入的 handler 强制转换为 HandlerFunc 类型,故而实现了 Handler 接口。http.ListenAndServe 参数中的 handler 通常为 nil,在这种情况下使用 DefaultServeMux。

http.ListenAndServe

ListenAndServe.svg

mux.ServeHTTP

muxServeHTTP.svg

按顺序做了几件事:

  1. 实例化 Server
    1. 2. 调用 net.Listen("tcp", addr)监听端口
  2. 启动一个 for 循环,在循环体中 Accept 请求
  3. 对每个请求实例化一个 Conn,并且开启一个 goroutine 为这个请求进行服务 go c.serve()
  4. 启动一个 for 循环,在循环体中读取每个请求的内容 w, err := c.readRequest()
  5. 进入 serverHandler.ServeHTTP ,判断 handler 是否为空,为空就将 handler 设置为 DefaultServeMux

  6. 调用相应 handler 的 ServeHTTP,在这个例子中,下面就进入到 DefaultServeMux.ServeHTTP

  7. 进入 mux.ServeHTTP, 调用 mux.Handler ,根据 request 选择 handler
  8. 选择 handler:
    1. 判断是否有路由能满足这个 request (循环遍历 ServerMux 的 muxEntry)
    2. 如果有路由满足,调用这个路由 handler 的 ServeHTTP
    3. 如果没有路由满足,调用 NotFoundHandler 的 ServeHTTP
  9. 进入到这个 handler 的 ServeHTTP,即执行 mux.Handler(r).ServeHTTP(w, r)

Trick

  1. type Handler interface {
  2. ServeHTTP(ResponseWriter, *Request)
  3. }
  4. type HandlerFunc func(ResponseWriter, *Request)
  5. // ServeHTTP calls f(w, r).
  6. func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
  7. f(w, r)
  8. }

将这一段专门摘出来,分析它们之间的关系。这里将 HandlerFunc 定义为一个函数类型,因此以后当调用 HandlerFunc(f) 之后, f 就会成为 HandlerFunc 类型,同时实现了Handler 接口,并且调用 ServeHttp 方法实际上就是调用 f 的对应方法