深入理解Golang之http server的实现

2020-01-28 14:26:07王旭
对象加入到 []muxEntry 中,按照路由表达式长度排序。前者很好理解,但后者可能不太容易看出来有什么作用,这个问题后面再作分析。

自定义ServeMux

我们也可以创建自定义的 ServeMux 取代默认的 DefaultServeMux


package main

import (
 "fmt"
 "net/http"
)

func indexHandler(w http.ResponseWriter, r *http.Request) {
 fmt.Fprintf(w, "hello world")
}

func htmlHandler(w http.ResponseWriter, r *http.Request) {
 w.Header().Set("Content-Type", "text/html")
 html := `<!doctype html>
 <META http-equiv="Content-Type" content="text/html" charset="utf-8">
 <html lang="zh-CN">
   <head>
     <title>Golang</title>
     <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0;" />
   </head>
   <body>
    <div id="app">Welcome!</div>
   </body>
 </html>`
 fmt.Fprintf(w, html)
}

func main() {
 mux := http.NewServeMux()
 mux.Handle("/", http.HandlerFunc(indexHandler))
 mux.HandleFunc("/welcome", htmlHandler)
 http.ListenAndServe(":8001", mux)
}

NewServeMux() 可以创建一个 ServeMux 实例,之前提到 ServeMux 也实现了 ServeHTTP 方法,因此 mux 也是一个 Handler 对象。对于 ListenAndServe() 方法,如果传入的 handler 参数是自定义 ServeMux 实例 mux ,那么 Server 实例接收到的路由对象将不再是 DefaultServeMux 而是 mux

开启服务

首先从 http.ListenAndServe 这个方法开始:


func ListenAndServe(addr string, handler Handler) error {
 server := &Server{Addr: addr, Handler: handler}
 return server.ListenAndServe()
}

func (srv *Server) ListenAndServe() error {
 if srv.shuttingDown() {
  return ErrServerClosed
 }
 addr := srv.Addr
 if addr == "" {
  addr = ":http"
 }
 ln, err := net.Listen("tcp", addr)
 if err != nil {
  return err
 }
 return srv.Serve(tcpKeepAliveListener{ln.(*net.TCPListener)})
}

这里先创建了一个 Server 对象,传入了地址和 handler 参数,然后调用 Server 对象 ListenAndServe() 方法。

看一下 Server 这个结构体, Server 结构体中字段比较多,可以先大致了解一下:


type Server struct {
 Addr string // TCP address to listen on, ":http" if empty
 Handler Handler // handler to invoke, http.DefaultServeMux if nil
 TLSConfig *tls.Config
 ReadTimeout time.Duration
 ReadHeaderTimeout time.Duration
 WriteTimeout time.Duration
 IdleTimeout time.Duration
 MaxHeaderBytes int
 TLSNextProto map[string]func(*Server, *tls.Conn, Handler)
 ConnState func(net.Conn, ConnState)
 ErrorLog *log.Logger

 disableKeepAlives int32  // accessed atomically.
 inShutdown  int32  // accessed atomically (non-zero means we're in Shutdown)
 nextProtoOnce  sync.Once // guards setupHTTP2_* init
 nextProtoErr  error  // result of http2.ConfigureServer if used

 mu   sync.Mutex
 listeners map[*net.Listener]struct{}
 activeConn map[*conn]struct{}
 doneChan chan struct{}
 onShutdown []func()
}