http是go自帶的web開發(fā)庫,,具有非常強(qiáng)大的web開發(fā)功能,。本文以一個(gè)代碼為例講解請(qǐng)求的解析過程,。
如下代碼為例
http.HandleFunc('/byte', sayByte) http.ListenAndServe(':8080', nil) func sayByte(writer http.ResponseWriter, request *http.Request) { writer.Write([]byte(' say byte byte!!'))
1. 路由注冊
http.HandleFunc('/byte', sayByte)
1.1 此行代碼會(huì)調(diào)用系統(tǒng)默認(rèn)的ServeMux即DefaultServeMux,,DefaultServeMux是http庫定義的一個(gè)變量。
DefaultServeMux.HandleFunc(pattern, handler) // serve.go 2380行
1.2 并且利用HandlerFunc將函數(shù)sayByte轉(zhuǎn)換成handler,,
mux.Handle(pattern, HandlerFunc(handler)) // serve.go 2368行
1.3 真正向DefaultServeMux中注冊路由和handler的是ServeMux的handle函數(shù)
func (mux *ServeMux) Handle(pattern string, handler Handler) { // serve.go 2342 panic('http: invalid pattern') panic('http: nil handler') if _, exist := mux.m[pattern]; exist { panic('http: multiple registrations for ' + pattern) mux.m = make(map[string]muxEntry) mux.m[pattern] = muxEntry{h: handler, pattern: pattern}
1.4 查看ServeMux結(jié)構(gòu)可知,,路由和handler存儲(chǔ)在ServeMux的m屬性中,m是一個(gè)map
type ServeMux struct { //serve.go 2133 hosts bool // whether any patterns contain hostnames
到此完成DefaultServeMux的初始化,,也就是路由與handler的一一對(duì)應(yīng)關(guān)系,,存儲(chǔ)在一個(gè)map中,鍵是路由,,值是muxEntry,,而由他存儲(chǔ)路由與handler。
2.服務(wù)開啟
http.ListenAndServe(':8080', nil)
2.1 監(jiān)聽端口
ln, err := net.Listen('tcp', addr) //serve.go 2707
2.2 接受請(qǐng)求
rw, e := l.Accept() //serve.go 2770
2.3 為請(qǐng)求創(chuàng)建一個(gè)連接
c := srv.newConn(rw) //serve.go 2793
2.4 開始服務(wù)
go c.serve(ctx) //serve.go 2795
2.5 初始化ServerHandler,,并且調(diào)用他的ServeHTTP方法
serverHandler{c.server}.ServeHTTP(w, w.req) // serve.go //1830
2.6 ServeHttp方法會(huì)找出服務(wù)的一個(gè)ServeMux,,如果沒有用戶自己沒有初始化一個(gè)ServeMux,則會(huì)使用DefaultServeMux,,也就是之前默認(rèn)初始化的ServeMux,,最后調(diào)用ServeMux的serveHTTP方法。
func (sh serverHandler) ServeHTTP(rw ResponseWriter, req *Request) { //serve.go 2686 handler := sh.srv.Handler handler = DefaultServeMux if req.RequestURI == '*' && req.Method == 'OPTIONS' { handler = globalOptionsHandler{} handler.ServeHTTP(rw, req)
2.7 在ServeMux的serveHTTP方法中,,找到處理函數(shù)并調(diào)用
func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) { //serve.go 2328 if r.ProtoAtLeast(1, 1) { w.Header().Set('Connection', 'close') w.WriteHeader(StatusBadRequest) h, _ := mux.Handler(r) //根據(jù)url在ServeMux中的m屬性中找到處理函數(shù),, h.ServeHTTP(w, r) //調(diào)用處理函數(shù)
2.8 尋找處理函數(shù)的代碼
func (mux *ServeMux) handler(host, path string) (h Handler, pattern string) { /serve.go 2309 // Host-specific pattern takes precedence over generic ones h, pattern = mux.match(host + path) h, pattern = mux.match(path) h, pattern = NotFoundHandler(), ''
func (mux *ServeMux) match(path string) (h Handler, pattern string) { // serve.go 2197 // Check for exact match first. // Check for longest valid match. for k, v := range mux.m { if h == nil || len(k) > n {
注意:觀察到ServeMux的m屬性的值是muxEntry,結(jié)構(gòu)如下
type muxEntry struct { //serve.go 2139
此處的handler是一個(gè)接口,,在如下代碼中,,我們傳入的是函數(shù),最終由HandlerFunc將函數(shù)轉(zhuǎn)成Handler,。
http.HandleFunc('/byte', sayByte)
我們也可以直接實(shí)現(xiàn)Handler ,那么此時(shí)代碼如下
func (h *MyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, 'Hello World!') http.Handle('/hello',&handler) http.ListenAndServe(':8080',nil)
文章到此為止,,介紹了
1.ServeMux的初始化過程
2.web請(qǐng)求處理過程
文中如果有錯(cuò)誤還請(qǐng)嚴(yán)厲指出。
|