2.Golang的Http源碼閱讀(Handler註冊)

來源:互聯網
上載者:User

先貼一段代碼

package mainimport (    "net/http"    "fmt"    "log")func hello(w http.ResponseWriter, r *http.Request)  {    r.ParseForm()    fmt.Printf("%+v\n", *r.URL)    fmt.Fprintln(w, "Hello world")}func main() {    http.HandleFunc("/", hello)    err := http.ListenAndServe(":9090", nil)    if err != nil {        log.Fatal(err)    }}

這裡監聽本地的9090連接埠,使用 http.HandleFunc 將URL為“/”的請求將其轉向名為hello的方法。這是比較常見的Golang的簡單Web的實現,但是看著會覺得很奇怪,建議先把代碼跑起來,然後我們再來看看源碼中Handler的定義先。

type Handler interface {    ServeHTTP(ResponseWriter, *Request)}

如代碼中所示,Handler實際上一個介面,實現了 ServeHTTP(ResponseWriter, *Request) 這個函數,就相當於實現了一個Handler。通俗講Handler就是處理輸入輸出資料流的函數,將Handler註冊到路由器,等同於將特定的URL跟這個函數綁定起來,當用戶端請求訪問這個URL,路由器就會使用這個函數進行操作。
可能會有童鞋會疑問,hello這個函數並不是一個Handler,為什麼可以作為Handler註冊一個URL。這是因為這裡有一個函數叫做HandleFunc,這裡就講講HandleFunc的原理吧。先把源碼列出來:

func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {    DefaultServeMux.HandleFunc(pattern, handler)}

HandleFunc傳入一個字串(URL)和一個func(ResponseWriter, Request),hello這個函數是符合func(ResponseWriter, Request)的要求的,然後使用DefaultServeMux進行處理,DefaultServeMux又是什嗎?在server.go的源碼中可以輕鬆找到DefaultServeMux的定義

type ServeMux struct {    mu    sync.RWMutex    m     map[string]muxEntry    hosts bool // whether any patterns contain hostnames}....// DefaultServeMux is the default ServeMux used by Serve.var DefaultServeMux = &defaultServeMuxvar defaultServeMux ServeMux

由源碼可以知道DefaultServeMux相當於一個公用的路由,一個公有變數,URL和Handle就是註冊到這個路由上的。需要注意的是ServeMux的成員變數,有一個sync.RWMutex,瞭解過Golang並發的應該知道,這是一個讀寫鎖(Mutiple read,single write lock, 多讀單寫鎖,允許多個讀操作並存執行,但寫操作會完全互斥,在讀取操作比較頻繁時比sync.Mutex有著更好的效能表現),這應該也是考慮到作為Web伺服器,讀取操作會比較頻繁。接下來看mux.Handle(pattern, HandlerFunc(handler))去到哪一步,應該看到這裡有一個函數HandlerFunc(handler):

type HandlerFunc func(ResponseWriter, *Request)// ServeHTTP calls f(w, r).func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {    f(w, r)}

看到這裡你就應該明白,為什麼hello這個函數沒有實現Handler方法也是一個Handler,因為HandlerFunc把hello強制實現ServeHTTP(w ResponseWriter, r *Request),所以hello這個函數也就是一個Handler。

這裡是路由的最後一步了

type muxEntry struct {    h       Handler    pattern string}// Handle registers the handler for the given pattern.// If a handler already exists for pattern, Handle panics.func (mux *ServeMux) Handle(pattern string, handler Handler) {    mux.mu.Lock()    defer mux.mu.Unlock()    if pattern == "" {        panic("http: invalid pattern")    }    if handler == nil {        panic("http: nil handler")    }    if _, exist := mux.m[pattern]; exist {        panic("http: multiple registrations for " + pattern)    }    if mux.m == nil {        mux.m = make(map[string]muxEntry)    }    mux.m[pattern] = muxEntry{h: handler, pattern: pattern}    if pattern[0] != '/' {        mux.hosts = true    }}

公有變數DefaultServeMux將Handler註冊,這裡就用到了讀寫鎖以及一個私人結構muxEntry,到這裡,路由註冊就結束了。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.