golang中ServeMux解析

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

ServeMux解析

  • 總覽
  • ServeMux結構體
  • NewServeMux
  • pathMatch
  • * ServeMux.Handler
  • * ServeMux.handler
  • * ServeMux.Handle
  • * ServeMux.ServeHTTP

總覽

本來是想做一個UML出來讓這篇解析更清晰一點的,但是markdown的UML文法我一直搗鼓不出來。試了幾個軟體感覺也沒有
想象中的好用和方便,看來是時候自己開發一個了(笑).
口述一個流程,具體的函數大家可以頁內跳轉去看.
首先我們是通過ListenAndServe來監聽本地連接埠的,之後ListenAndServe將收到的建立一個Response連同收到的Request
作為參數調用ServeMux結構體的ServeHTTP(省略了中間過程).ServeHTTP將
Request作為參數調用
Handler函數,Handler的傳回值為一個Handler類型的介面,ServeHTTP會調用介面實現的ServeHTTP處理Response.

如果Request.URL.Path中有不合法的內容,則調用cleanPath清理,隨後將Request.Host以及清理後的
內容傳入handler函數,隨後返回一個RedirectHandler以及handler所返回的路徑。如果
Request.URL.Path合法,那麼
直接調用handler,傳回值與handler傳回值相同。

handler中通過判斷ServeMux.hosts來決定是否實現pattern = r.Host + r.URL.Path.之後將pattern作為參數調用match,並將
match的傳回值返回.

match的判別方式比較"有趣",它雖然沒實現為樹形結構(只是用了映射),但是搜尋的方法就是樹形,因為URL路徑就是個樹形.它按照樹的根節點
與子節點的關係進行判斷,譬如路徑"/home/select/usercourse",match在匹配的時候會首先匹配到"/"(假如我們註冊了),其次是"/home",
之後逐層匹配下來,假如我們沒註冊過"/home/select/usercourse",但是註冊了"/home/select/",那麼match就會匹配到這一層.然後返回
"/home/select/"的Handler以及url(pattern).match函數的匹配規則實現在pathMatch

ServeMux結構體

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    }

這樣看起來還蠻直觀的,mu是一個互斥鎖,m則是我們所要用的路由(router),其中的鍵(key)則是我們掛載的路徑,
對應的值則是響應的muxEntry,hosts指明了我們是否在每個路徑中都聲明了hostnames.比如我們平常用'/'來表示
掛載在網域名稱根目錄下的HandlerFunc,但是如果hosts=true,那麼我們就需要'127.0.0.1/'來做同樣的事情了.

下面我們來看muxEntry,h比較明確,就是我們註冊的處理過程.pattern與ServeMux中m的key相同,也就是說是我們
註冊的路徑,而explicit的用途其實是比較隱晦的。程式會根據explicit判別這個路徑的Handler是否是使用者註冊的。
如果是程式為了Redirect(詳細點擊這裡)而設定的,那麼在它是可以被覆蓋的,否則就是不可以被覆蓋的.

NewServeMux()

DefaultServeMux變數就是直接調用的這個函數。那麼這個函數只make了一個變數m,也就是為map分配了空間。
在golang的文法中,結構體裡未聲明的變數也是存在的(即分配了記憶體),只不過是該類型的預設值,比如hosts就
被設定成了false.這個問題不過多解釋,有興趣的話可以看一下golang中的相關內容

pathMatch()

這個函數是ServeMux用來匹配路徑的主要函數,所以看一下策略還是很重要的.
函數中的參數pattern是我們註冊的路徑,path是使用者請求的路徑

func pathMatch(pattern, path string) bool {    if len(pattern) == 0 {        // should not happen        return false    }    n := len(pattern)    if pattern[n-1] != '/' {        return pattern == path    }    return len(path) >= n && path[0:n] == pattern}

如果我們掛載的路徑不是以'/'結尾的,那麼就直接判斷兩個參數是否相同。如果是以'/'結尾的,只要path的路徑包含
pattern那麼就被判定是匹配。也就是說,如果我註冊了/home/select/,那麼/home/select/hello也會被定位到/home/select/
掛載的HandlerFunc上.這樣做相當於為路徑設定了一個index,不符合規則的URL都會被Redirect到這個index上

* ServeMux.Handler()

注釋寫的很清楚,這個函數就是處理URL,然後調用*ServeMux.handler().首先調用cleanPath清理請求URL中的不合法內容。如果存在不合法內容,
則將清理過的URL交由*ServeMux.handler()處理並獲得匹配到的pattern,然後修改url.Path的內容並調用RedirectHandler.
如果內容合法,則直接調用*ServeMux.handler()並返回結果

* ServeMux.handler()

調用ServeMux.match()(封裝了pathMatch函數)來獲得匹配到的Handler以及對應pattern,如果ServeMux.hosts==true,那麼
傳入的參數為host + path,如果找不到的話,調用NotFoundHandler函數,並將其結果返回.

* ServeMux.Handle()

Handle函數是用來註冊路徑與處理過程的.如果該路徑已經存在了一個使用者註冊的Handler則會panic(意思就是說不支援覆蓋).判別了合法參數以後就將
pattern作為key,建立一個muxEntry類型變數作為value加入到map中。

if pattern[0] != '/' {    mux.hosts = true}

這是這個函數中比較有意思的一個部分,通過這裡我們可以看到如果註冊路徑的時候並不是以'/'開頭的,那麼ServeMux就會開啟hosts,然後會在
請求到達的時候將URL.Host和URL.Path串連在一起放入match中尋找,具體資訊請看這裡

接下來是關於路徑的處理,也就是關於"/home"與"/home/"的區別.我們先來看看作者怎麼說

    // Helpful behavior:    // If pattern is /tree/, insert an implicit permanent redirect for /tree.    // It can be overridden by an explicit registration.

如果路徑的末尾是以'/'結尾並且該路徑去掉末尾的'/'以後並沒有被註冊.那麼將會去掉'/'並且為其綁定一個Redirect到現在的路徑.
我自己寫起來都覺得繞,舉個例子就清楚了.
我註冊了一個路徑"/home/",但是沒有註冊"/home",那麼如果使用者訪問了"/home"會發生什麼呢?是的,會被Redirect到"/home/".
需要注意的是,這裡的muxEntry中的explicit沒有填,也就是說是false,那麼即是可以覆蓋的.

* ServeMux.ServeHTTP()

ServeHTTP會檢測非法的URI(* )
如果通過檢測就會調用自身的Handler()來返回註冊的Handler,隨後調用Handler的ServeHTTP方法

聯繫我們

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