Golang學習筆記 - 標準庫"net/http"的簡析及自製簡單路由架構

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

原文連結:http://targetliu.com/golang-http-router/

還是在繼續學習Go的路上,曾經在使用PHP的時候吃過過度依賴架構的虧。現在學習Go的時候決定先打好基礎,從標準庫學起走。

源碼分析

我們知道最簡單的建立http伺服器代碼基本上都是這樣的:

http.HandleFunc('/', func(w http.ResponseWriter, r *http.Request){    fmt.Fprint(w, "Hello world")})http.ListenAndServe(":8080", nil)

這樣就成功的建立了一個監聽 8080 連接埠的http伺服器,當訪問的時候輸出 Hello world

我們順藤摸瓜來看看 HandleFunc 做了些什麼事:

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

這裡繼續通過調用 DefaultServeMuxHandleFunc 方法註冊路由,這個 DefaultServeMux 又是何方聖神:

type ServeMux struct {    mu    sync.RWMutex    m     map[string]muxEntry    hosts bool // whether any patterns contain hostnames}type muxEntry struct {    explicit bool    h        Handler    pattern  string}// NewServeMux allocates and returns a new ServeMux.func NewServeMux() *ServeMux { return new(ServeMux) }// DefaultServeMux is the default ServeMux used by Serve.var DefaultServeMux = &defaultServeMuxvar defaultServeMux ServeMux

DefaultServeMuxnet/http 包提供的一個預設的 ServeMux 類型,ServeMux 實現了 Handler 介面。

追根究底,發現http伺服器收到一條請求後通過 go c.serve(ctx) 開啟goroutine 處理這個請求,在這個過程中調用了 Handler 介面函數 ServeHTTP 來做進一步的處理(比如匹配方法、連結等等)。

所以,我們就可以理解 ServeMux 就是 net/http 一個內建的路由功能。

繼續回到 HandleFunc 來:

func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {    mux.Handle(pattern, HandlerFunc(handler))}

ServeMuxHandleFunc 方法將我們傳入的路由具體實現函數轉換成 HandlerFunc 類型並通過 Handle 註冊到路由。這個 HandlerFunc 類型也實現了 Handler 介面:

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

最後到了 Handle 這個方法, Handle 方法通過將 pattern 路徑以及實現了 Handler 介面的方法一一對應的儲存到 ServeMuxmap[string]muxEntry 中,方便後續請求的時候調用。因此,也可以通過 Handle 直接傳入一個實現了 Handler 介面的方法註冊路由。

至此,net/http 包中預設路由的註冊過程基本上已經走完。

至於請求的時候路由調用,記住通過 ServeHTTP 尋找 map 中對應路徑並調用相關方法就行了。

自製路由

通過以上的分析,我們可以依樣畫葫蘆,實現自己的路由功能。

package routeimport (    "net/http"    "strings")//返回一個Router執行個體func NewRouter() *Router {    return new(Router)}//路由結構體,包含一個記錄方法、路徑的maptype Router struct {    Route map[string]map[string]http.HandlerFunc}//實現Handler介面,匹配方法以及路徑func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {    if h, ok := r.Route[req.Method][req.URL.String()]; ok {        h(w, req)    }}//根據方法、路徑將方法註冊到路由func (r *Router) HandleFunc(method, path string, f http.HandlerFunc) {    method = strings.ToUpper(method)    if r.Route == nil {        r.Route = make(map[string]map[string]http.HandlerFunc)    }    if r.Route[method] == nil {        r.Route[method] = make(map[string]http.HandlerFunc)    }    r.Route[method][path] = f}

使用:

r := route.NewRouter()r.HandleFunc("GET", "/", func(w http.ResponseWriter, r *http.Request) {    fmt.Fprint(w, "Hello Get!")})r.HandleFunc("POST", "/", func(w http.ResponseWriter, r *http.Request) {    fmt.Fprint(w, "hello POST!")})http.ListenAndServe(":8080", r)

這個例子只是依樣畫葫蘆的簡易功能實現。

一個完整的路由架構應該包含更複雜的匹配、錯誤偵測等等功能,大家可以試著自己動手試試。

閱讀源碼和重複造輪子都是學習的方法。

最後,歡迎大家關注我的部落格http://targetliu.com/

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.