| http是go自帶的web開發(fā)庫,具有非常強(qiáng)大的web開發(fā)功能。本文以一個代碼為例講解請求的解析過程。 如下代碼為例    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 此行代碼會調(diào)用系統(tǒng)默認(rèn)的ServeMux即DefaultServeMux,DefaultServeMux是http庫定義的一個變量。 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存儲在ServeMux的m屬性中,m是一個map type ServeMux struct {   //serve.go 2133   hosts bool // whether any patterns contain hostnames
 到此完成DefaultServeMux的初始化,也就是路由與handler的一一對應(yīng)關(guān)系,存儲在一個map中,鍵是路由,值是muxEntry,而由他存儲路由與handler。 2.服務(wù)開啟http.ListenAndServe(':8080', nil) 2.1 監(jiān)聽端口 ln, err := net.Listen('tcp', addr) //serve.go 2707
 2.2 接受請求 rw, e := l.Accept()  //serve.go 2770
 2.3 為請求創(chuàng)建一個連接 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方法會找出服務(wù)的一個ServeMux,如果沒有用戶自己沒有初始化一個ServeMux,則會使用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是一個接口,在如下代碼中,我們傳入的是函數(shù),最終由HandlerFunc將函數(shù)轉(zhuǎn)成Handler。 http.HandleFunc('/byte', sayByte) 我們也可以直接實(shí)現(xiàn)Handler ,那么此時代碼如下 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請求處理過程 文中如果有錯誤還請嚴(yán)厲指出。 |