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 {
Addr string // 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.
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()
}
可見 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 {
mu sync.RWMutex
m map[string]muxEntry // 對映表
hosts bool // whether any patterns contain hostnames
}
type muxEntry struct {
h Handler
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
介面的處理物件。效果是一致的。
完!
原文出自:小韓說課
微信關注:小韓說課