http

简单的一个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, ""
}