流程概括

首先来大体上抽象一下Go服务器的基本运行流程。

  1. 创建 Listen Socket ,并将其绑定到对应的监听端口上。
  2. 等待并接受客户端发送的请求,从而获取 Client Socket ,程序将通过它获取http的请求头以及body内容(POST)。
  3. 根据请求的Path以及内部逻辑选择对应的的 请求处理函数 来处理相应的请求。
  4. 将处理结果发送回Client Socket ,并通过它写回客户端。

源码追踪

关联结构

http.ListenAndServestringServeMux
HandlerServeHTTP

自定义路由

先来看一下自定义路由选择器,它的实现逻辑相对比较简单:

type MyMux struct {}

//实现Handler接口
func (m *MyMux)ServeHTTP(w http.ResponseWriter, r *http.Request) {
	...(自定义路由选择逻辑)
}
func main() {
	mux := &MyMux{}
	err := http.ListenAndServe(":9090", mux)
}

(这部分代码在最底下有完整版作为直观感受)

默认路由

之后就来看一下当使用默认路由时所涉及的内部结构吧:

func sayhelloName(w http.ResponseWriter, r *http.Request) {
	...(自定义请求处理函数)
}

func main() {
	http.HandleFunc("/", sayhelloName) //设置访问的路由
	err := http.ListenAndServe(":9090", nil) //设置监听的端口
}
  • 首先来看一下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
}
mumHandler
// ServeHTTP dispatches the request to the handler whose
// pattern most closely matches the request URL.
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)
}
Handler
  • 路由规则存储匹配字符串以及对应的请求处理接口。
type muxEntry struct {
	h       Handler
	pattern string
}
ServeHttp
type Handler interface {
	ServeHTTP(ResponseWriter, *Request)
}
HandlerFuncHandler
type HandlerFunc func(ResponseWriter, *Request)

// ServeHTTP calls f(w, r).
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
	f(w, r)
}

运行流程

现在来正式过一遍Go http的执行经过:
这里将源码中参数设置,错误检查以及一些非主要流程的相关代码给省去了,标记为:(…)
那么就从main开始吧:

func main() {
	http.HandleFunc("/", sayhelloName)
	err := http.ListenAndServe(":9090", nil)
}
http.ListenAndServe
func ListenAndServe(addr string, handler Handler) error {
	server := &Server{Addr: addr, Handler: handler}
	return server.ListenAndServe()
}
Server.ListenAndServe
func (srv *Server) ListenAndServe() error {
	(...)
	ln, err := net.Listen("tcp", addr)
	(...)
	return srv.Serve(tcpKeepAliveListener{ln.(*net.TCPListener)})
}
Server.Servenet.Listener.AcceptServer.newConn
func (srv *Server) Serve(l net.Listener) error {
	(...)
	for {
		rw, e := l.Accept()
		(...)
		c := srv.newConn(rw)
		c.setState(c.rwc, StateNew) // before Serve can return
		go c.serve(ctx)
	}
}
conn.serveServeHttp
func (c *conn) serve(ctx context.Context) {
	for {
		w, err := c.readRequest(ctx)
		(...)
		// Expect 100 Continue support
		req := w.req
		(...)
		serverHandler{c.server}.ServeHTTP(w, w.req)
		w.cancelCtx()
		if c.hijacked() {
			return
		}
		w.finishRequest()
		(...)
	}
}
// serverHandler delegates to either the server's Handler or
// DefaultServeMux and also handles "OPTIONS *" requests.
type serverHandler struct {
	srv *Server
}

func (sh serverHandler) ServeHTTP(rw ResponseWriter, req *Request) {
	handler := sh.srv.Handler
	if handler == nil {
		handler = DefaultServeMux
	}
	if req.RequestURI == "*" && req.Method == "OPTIONS" {
		handler = globalOptionsHandler{}
	}
	handler.ServeHTTP(rw, req)
}

还有就是一些细节上的工作,包括验证,有效时间等等。但在程序提供服务时的主要逻辑就是以上的途径了。


附加

ServeMux

(不需要弄明白每一步的逻辑,毕竟只是截取的一部分,但应该很容易看明白它在干些什么)

type MyMux struct {}

func (m *MyMux)ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if strings.HasPrefix(r.URL.Path, "/static") {
		http.ServeFile(w, r, "./web/"+r.URL.Path)
	}  else {
		switch r.URL.Path {
		case "/":
			sayHello(w, r)
			return
		case "/login":
			service.Login2(w, r)
			return
		case "/upload":
			service.Upload(w, r)
			return
		case "/view":
			service.View(w, r)
			return
		default:
			http.NotFound(w, r)
			return
		}
	}
}

func sayHello(w http.ResponseWriter, r *http.Request) {
	var name string
	cookie, err := r.Cookie("username")
	if err != nil || cookie.Value == "" {
		name = "tourist"
	}else {
		name = cookie.Value
	}
	_, _ = fmt.Fprintf(w, "Hello, %s", name)
}

func main() {
	mux := &MyMux{}
	err := http.ListenAndServe(":9090", mux)
	if err != nil {
		log.Fatal("ListenAndServe:", err)
	}
}
ServeMuxHandlerFuncHandlerServeHTTP