Go語言中處理 HTTP 伺服器
1 概述
包 net/http
提供了HTTP伺服器端和客戶端的實現。本文說明關於伺服器端的部分。
快速開始:
package main import ( "log" "net/http" ) func main() { // 設定 路由 http.HandleFunc("/", IndexAction) // 開啟監聽 log.Fatal(http.ListenAndServe(":8888", nil)) } func IndexAction(w http.ResponseWriter, r *http.Request) { w.Write([]byte(`<h1 align="center">來自小韓說課的問候</h1>`)) }
執行程式,在瀏覽器上請求: localhost:8888
,你會看到我們的結果:
Go語言構建HTTP伺服器還是很容易的。深入說明。
2 http.Server 型別
HTTP 伺服器在 Go 語言中是由 http.Server
結構體物件實現的。參考 http.ListenAndServe()
的實現:
// 檔案:src/net/http/server.go // ListenAndServe always returns a non-nil error. func ListenAndServe(addr string, handler Handler) error { server := &Server{Addr: addr, Handler: handler} return server.ListenAndServe() }
可見過程是先例項化 Server
物件,再完成 ListenAndServe
。其中 Serve
物件就是表示 HTTP 伺服器的物件。其結構如下 :
// 檔案:src/net/http/server.go type Server struct { Addrstring// TCP 監聽地址, 留空為:":http" Handler Handler // 呼叫的 handler(路由處理器), 設為 nil 表示 http.DefaultServeMux TLSConfig *tls.Config // TLS 配置物件 ReadTimeout time.Duration // 請求超時時長 ReadHeaderTimeout time.Duration // 請求頭超時時長 WriteTimeout time.Duration // 響應超時時長 IdleTimeout time.Duration // 請求空閒時長(keep-alive下兩個請求間) MaxHeaderBytes int // 請求頭的最大長度 TLSNextProto map[string]func(*Server, *tls.Conn, Handler) // NPN 型協議升級出現時接管TLS連線的處理器函式對映表 ConnState func(net.Conn, ConnState) // 狀態轉換事件處理器 ErrorLog *log.Logger // 日誌記錄物件 disableKeepAlives int32// accessed atomically. inShutdownint32// accessed atomically (non-zero means we're in Shutdown) nextProtoOncesync.Once // guards setupHTTP2_* init nextProtoErrerror// result of http2.ConfigureServer if used musync.Mutex listenersmap[*net.Listener]struct{} activeConn map[*conn]struct{} doneChanchan struct{} onShutdown []func() }
可見 Server
定義了伺服器需要的資訊。
例項化了 Server
物件後,呼叫其 (srv *Server) ListenAndServe() error
方法。該方法會監聽 srv.Addr
指定的 TCP 地址,並通過 (srv *Server) Serve(l net.Listener) error
方法接收瀏覽器端連線請求。 Serve
方法會接收監聽器 l 收到的每一個連線,併為每一個連線建立一個新的服務程序。
該 go 程序會讀取請求,然後呼叫 srv.Handler
處理並響應。 srv.Handler
通常會是 nil,這意味著需要呼叫 http.DefaultServeMux
來處理請求,這個 DefaultServeMux
是預設的路由,我們使用 http.HandleFunc
就是在 http.DefaultServeMux
上註冊方法。
3 http.DefaultServeMux 預設路由物件
看 Go 的原始碼,瞭解 http.HandleFunc():
func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) { DefaultServeMux.HandleFunc(pattern, handler) }
可以看出來,註冊的函式被 DefaultServerMux
來使用了。註冊的時候,需要 pattern,就是 URL 模式,以及處理該 URL 模式的函式。
DefaultServerMux
是 http.ServeMux
型別的一個預設例項, ServeMux
就是路由。其主要結構是一個對映 map,用來儲存 URL 模式和相關處理函式的關係。參看原始碼可以看出來:
type ServeMux struct { musync.RWMutex mmap[string]muxEntry // 對映表 hosts bool // whether any patterns contain hostnames } type muxEntry struct { hHandler pattern string }
可以呼叫多次 http.HandleFunc()
來註冊多個處理器。
URL 模式是固定的、由根開始的路徑。處理器的 URL 模式匹配原則是 左側長度優先匹配 。 例如有模式 /path/article/
和 /path/
,如果請求的 URL 是 /path/other/
會由 /path/
註冊的處理器來處理,而 URL 為 /path/article/42/
會由 /path/article/
來處理。
以斜槓結尾的模式代表一個由根開始的子樹,就是以當前為字首的都會匹配。因此 /
會匹配所有的未被其他註冊的模式匹配的路徑。
4 處理器
處理器可以由函式或實現 Handler
介面的物件來充當。 Handler
介面就是要求物件實現和處理器函式一致的方法。看 http.Handler
介面的實現原始碼:
type Handler interface { ServeHTTP(ResponseWriter, *Request) }
我們使用函式 http.HandleFunc
註冊處理函式,而使用 http.Handle
函式來註冊滿足 Handler
介面的處理物件。效果是一致的。