Golang | HttpRouter

_Liu_發表於2020-04-04

1、什麼是httprouter

httprouter談不上是一個框架,它的效能非常優秀。完全可以用來代替預設的 ServeMux

所以比較適合對效能要求高,路由相對簡單扁平的業務,或者作為高層HTTP框架的內部模組。

httproute內部通過實現一個trie樹來提高效能。

核心程式碼就是golang標準庫中 http.Handler 介面,在該函式中實現自己的請求路由分發策略。

gorilla/mux也是一個第三方的路由器,但是效能一般

2、為什麼用httprouter

說說net/http的不足:
  • 不能單獨的對請求方法(POST,GET等)註冊特定的處理函式
  • 不支援路由變數引數
  • 不能自動對Path進行校準
  • 效能一般、擴充套件性不足
httprouter帶來哪些便利?
  • 僅支援精確匹配,及只匹配一個模式或不會匹配到任何模式。相對於其他一些mux,例如go原生的 http.ServerMux, 會使得一個請求URL匹配多個模式,從而需要有優先順序順序,例如最長匹配、最先匹配等等。
  • 不需要關心URL結尾的斜槓
  • 路徑自動歸一化和矯正
  • 零記憶體分配、高效能

3、httprouter路由匹配

net/http的路由匹配
//	/api,可以訪問到
//	/api/,不可以
http.HandleFunc("/api",func(w http.ResponseWriter,r *http.Request){
	fmt.Println("/api")
})

//	/api,可以
//	/api/,也可以
http.HandleFunc("/api/",func(w http.ResponseWriter,r *http.Request){
	fmt.Println("/api")
})
複製程式碼
httprouter的路徑匹配規則

兩個路由命名捕獲方式:(==路由命名的捕獲,不是路由引數的捕獲==)

  • :name named parameter (只能根據路由命名進行捕獲)
  • *name catch-all parameter (*表示捕獲任意內容)

其中:name的捕獲方式是匹配內容直到下一個斜線或者路徑的結尾。例如要為如下路徑註冊 handler:

Path: /blog/:category/:post  
router.GET("/blog/:category/:post", Hello) //(category/post可以看成是一個變數)
	
當請求路徑為:
/blog/go/request-routers            match: category="go", post="request-routers"
/blog/go/request-routers/           no match, but the router would redirect
/blog/go/                           no match
/blog/go/request-routers/comments   no match
複製程式碼

*name的捕獲方式是從指定位置開始 (包含字首 "/") 匹配到結尾:

Path: /files/*filepath     */
router.GET("/files/*filepath", Hello) //filepath可以看成是一個變數

當請求路徑為:
/files/                             match: filepath="/"
/files/LICENSE                      match: filepath="/LICENSE"
/files/templates/article.html       match: filepath="/templates/article.html"
/files                              no match, but the router would redirect
複製程式碼

4、httprouter重定向

func New() *Router {
	return &Router{
		//是否啟用自動重定向。
        //比如請求/foo/,但是隻有/foo的handler,則httprouter內部使用301重定向到/foo進行GET處理。
        //檢視瀏覽器可以看到301的請求,可以看到請求頭的location:/foo
        
        //直接get,然後響應一個字串,這裡的文字型別是text/plain,其實就是txt檔案
        //這也就為什麼,只有/foo的handler時,請求/foo/會404,因為/foo/代表著foo目錄,預設會請求/foo/index.html,不就404了
        RedirectTrailingSlash:  true,
        
	RedirectFixedPath:      true,
		
        HandleMethodNotAllowed: true,
		
        //如果啟用,則路由器會自動回覆OPTIONS請求
        HandleOPTIONS:          true,
	}
}
複製程式碼

5、lookup

func (r *Router) Lookup(method, path string) (Handle, Params, bool)
複製程式碼

Lookup根據method+path檢索對應的Handle,以及Params,並可以通過第三個返回值判斷是否會進行重定向。

6、關於引數

除了路由引數,還有URL的query引數,也就是?a=b&c=d這樣的格式

query引數
//url引數解析
http.HandleFunc("/api/", func(w http.ResponseWriter, r *http.Request) {
    values := r.URL.Query()
    fmt.Println(values)
})

//result
//http://127.0.0.1:9090/api/?a=1&b=2&c=3
//map[a:[1] b:[2] c:[3]]
複製程式碼
路由引數
//使用場景有哪些呢??
/users/123
/users/456
/users/23456
比如有很多使用者,如上,我們需要為一個個使用者去註冊路由?顯然不現實
這時就可以使用路由引數了,/users/id
複製程式碼

相關文章