Example
package main
import (
"fmt"
"log"
"net/http"
)
func sayHello(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello World!")
}
func main() {
http.HandleFunc("/", sayHello)
err := http.ListenAndServe(":9090", nil)
if err != nil {
log.Fatal("ListenAndServe: ", err)
}
}
Execute Flow
http.HandleFunc
func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
DefaultServeMux.HandleFunc(pattern, handler)
}
func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
if handler == nil {
panic("http: nil handler")
}
mux.Handle(pattern, HandlerFunc(handler))
}
func (mux *ServeMux) Handle(pattern string, handler Handler) {
mux.mu.Lock()
defer mux.mu.Unlock()
...
if mux.m == nil {
mux.m = make(map[string]muxEntry)
}
e := muxEntry{h: handler, pattern: pattern}
mux.m[pattern] = e
if pattern[len(pattern)-1] == '/' {
mux.es = appendSorted(mux.es, e)
}
if pattern[0] != '/' {
mux.hosts = true
}
}
func appendSorted(es []muxEntry, e muxEntry) []muxEntry {
n := len(es)
i := sort.Search(n, func(i int) bool {
return len(es[i].pattern) < len(e.pattern)
})
if i == n {
return append(es, e)
}
// we now know that i points at where we want to insert
es = append(es, muxEntry{}) // try to grow the slice in place, any entry works.
copy(es[i+1:], es[i:]) // Move shorter entries down
es[i] = e
return es
}
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
}
var DefaultServeMux = &defaultServeMux
var defaultServeMux ServeMux
按顺序做了几件事:
- 调用了 DefaultServerMux 的 HandleFunc
- 调用了 DefaultServerMux 的 Handle
- 往 DefaultServeMux 的 map[string]muxEntry 中增加对应的 handler 和路由规则
直接调用 HandleFunc ,会间接调用 mux.HandleFunc ,之后 mux.Handle() 将传入的 handler 强制转换为 HandlerFunc 类型,故而实现了 Handler 接口。http.ListenAndServe 参数中的 handler 通常为 nil,在这种情况下使用 DefaultServeMux。
http.ListenAndServe
mux.ServeHTTP
按顺序做了几件事:
- 实例化 Server
2. 调用 net.Listen("tcp", addr)监听端口
- 启动一个 for 循环,在循环体中 Accept 请求
- 对每个请求实例化一个 Conn,并且开启一个 goroutine 为这个请求进行服务 go c.serve()
- 启动一个 for 循环,在循环体中读取每个请求的内容 w, err := c.readRequest()
进入 serverHandler.ServeHTTP ,判断 handler 是否为空,为空就将 handler 设置为 DefaultServeMux
调用相应 handler 的 ServeHTTP,在这个例子中,下面就进入到 DefaultServeMux.ServeHTTP
- 进入 mux.ServeHTTP, 调用 mux.Handler ,根据 request 选择 handler
- 选择 handler:
- 判断是否有路由能满足这个 request (循环遍历 ServerMux 的 muxEntry)
- 如果有路由满足,调用这个路由 handler 的 ServeHTTP
- 如果没有路由满足,调用 NotFoundHandler 的 ServeHTTP
- 进入到这个 handler 的 ServeHTTP,即执行 mux.Handler(r).ServeHTTP(w, r)
Trick
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
type HandlerFunc func(ResponseWriter, *Request)
// ServeHTTP calls f(w, r).
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
f(w, r)
}
将这一段专门摘出来,分析它们之间的关系。这里将 HandlerFunc 定义为一个函数类型,因此以后当调用 HandlerFunc(f) 之后, f 就会成为 HandlerFunc 类型,同时实现了Handler 接口,并且调用 ServeHttp 方法实际上就是调用 f 的对应方法