简单的一个hello world的http server如下:
package main import ( "io" "log" "net/http" ) func main() { // Hello world, the web server helloHandler := func(w http.ResponseWriter, req *http.Request) { io.WriteString(w, "Hello, world!\n") } http.HandleFunc("/hello", helloHandler) log.Fatal(http.ListenAndServe(":8080", nil)) }
看源码直接说明流程吧:
ListenAndServe
内部逻辑主要是新建一个Server对象,并调用Server对象的ListenAndServe
func ListenAndServe(addr string, handler Handler) error { server := &Server{Addr: addr, Handler: handler} return server.ListenAndServe() }
Server对象的ListenAndServe
主要做了两件事,第一件是创建对指定地址和端口的tcp监听,并返回listener,然后传入listener并继续调用Server对象的Serve方法。
func (srv *Server) ListenAndServe() error { ... ln, err := net.Listen("tcp", addr) if err != nil { return err } return srv.Serve(ln)
Server对象的Serve
主要做的事情是:不断循环等待有tcp连接建立,如果有tcp连接,单独起协程去处理。
func (srv *Server) Serve(l net.Listener) error { ... for { rw, err := l.Accept() ... c := srv.newConn(rw) ... go c.serve(connCtx) } }
而协程处理的逻辑server
主要是不断循环读取http请求,并处理http请求。
func (c *conn) serve(ctx context.Context) { ... for { // Read next request from connection. w, err := c.readRequest(ctx) ... serverHandler{c.server}.ServeHTTP(w, w.req) } }
ServeHTTP主要的逻辑是,如果调用ListenAndServe的第二个参数Handler为空,就用默认的DefaultServeMux作为Handler,否则用指定的。
然后调用ServeHTTP方法。我们传入的是nil,继续看DefaultServeMux的ServeHTTP实现。
func (sh serverHandler) ServeHTTP(rw ResponseWriter, req *Request) { handler := sh.srv.Handler if handler == nil { handler = DefaultServeMux } ... handler.ServeHTTP(rw, req) }
DefaultServeMux看起来陌生,其实我们回到http.HandleFunc("/hello", helloHandler的使用,
底层就是DefaultServeMux的封装
func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) { DefaultServeMux.HandleFunc(pattern, handler) }
HandleFunc的逻辑是调用Handle函数处理。
func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) { if handler == nil { panic("http: nil handler") } mux.Handle(pattern, HandlerFunc(handler)) }
mux.Handle的逻辑主要是存下pattern和handler的对应关系。所以http.HandleFunc("/hello", helloHandler)就是存pattern和handler的关系。
func (mux *ServeMux) Handle(pattern string, handler Handler) { ... checks e := muxEntry{h: handler, pattern: pattern} mux.m[pattern] = e if pattern[len(pattern)-1] == '/' { mux.es = appendSorted(mux.es, e) } ... }
我们把思路拉回到ListenAndServe函数最内部的逻辑[DefaultServeMux.ServeHTTP(https://sourcegraph.com/github.com/golang/[email protected]/-/blob/src/net/http/server.go?L2407&subtree=true)
部分,看看处理逻辑:
// ServeHTTP dispatches the request to the handler whose // pattern most closely matches the request URL. func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) { ... h, _ := mux.Handler(r) h.ServeHTTP(w, r) }
继续追mux.Handler,可以看到基本内容是根据host和path查找对应的handler:
// handler is the main implementation of Handler. // The path is known to be in canonical form, except for CONNECT methods. func (mux *ServeMux) handler(host, path string) (h Handler, pattern string) { ... // Host-specific pattern takes precedence over generic ones if mux.hosts { h, pattern = mux.match(host + path) } if h == nil { h, pattern = mux.match(path) } if h == nil { h, pattern = NotFoundHandler(), "" } return }
而查找逻辑mux.match主要是:如果有完全匹配,就直接返回,没有就查找最长匹配。
// Find a handler on a handler map given a path string. // Most-specific (longest) pattern wins. func (mux *ServeMux) match(path string) (h Handler, pattern string) { // Check for exact match first. v, ok := mux.m[path] if ok { return v.h, v.pattern } // Check for longest valid match. mux.es contains all patterns // that end in / sorted from longest to shortest. for _, e := range mux.es { if strings.HasPrefix(path, e.pattern) { return e.h, e.pattern } } return nil, "" }