HttpRouter是一個輕量級但卻很是高效的multiplexer。手冊:
https://godoc.org/github.com/julienschmidt/httprouter
https://github.com/julienschmidt/httprouterhtml
package main import ( "fmt" "github.com/julienschmidt/httprouter" "net/http" "log" ) func Index(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { fmt.Fprint(w, "Welcome!\n") } func Hello(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { fmt.Fprintf(w, "hello, %s!\n", ps.ByName("name")) } func main() { router := httprouter.New() router.GET("/", Index) router.GET("/hello/:name", Hello) log.Fatal(http.ListenAndServe(":8080", router)) }
首先執行:git
go get github.com/julienschmidt/httprouter
而後再啓動web服務:github
go run xxx.go
和http包的ServeMux用法其實很相似。上面定義了兩個httprouter中的handle,相似於http包中的http.HandlerFunc類型,具體的對應關係後文會解釋,只要認爲它是handler,是處理對應請求的就好了。而後使用New()方法建立了實例,並使用GET()方法爲兩個模式註冊了對應的handler。web
須要注意的是,第二個模式"/hello/:name",它能夠用來作命名匹配,相似於正則表達式的命名捕獲分組。後面會詳細解釋用法。正則表達式
Variables func CleanPath(p string) string type Handle type Param type Params func ParamsFromContext(ctx context.Context) Params func (ps Params) ByName(name string) string type Router func New() *Router func (r *Router) DELETE(path string, handle Handle) func (r *Router) GET(path string, handle Handle) func (r *Router) HEAD(path string, handle Handle) func (r *Router) Handle(method, path string, handle Handle) func (r *Router) Handler(method, path string, handler http.Handler) func (r *Router) HandlerFunc(method, path string, handler http.HandlerFunc) func (r *Router) Lookup(method, path string) (Handle, Params, bool) func (r *Router) OPTIONS(path string, handle Handle) func (r *Router) PATCH(path string, handle Handle) func (r *Router) POST(path string, handle Handle) func (r *Router) PUT(path string, handle Handle) func (r *Router) ServeFiles(path string, root http.FileSystem) func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request)
httprouter中的Handle相似於http.HandlerFunc,只不過它支持第三個參數Params。函數
type Handle func(http.ResponseWriter, *http.Request, Params) Handle is a function that can be registered to a route to handle HTTP requests. Like http.HandlerFunc, but has a third parameter for the values of wildcards (variables).
例如前面示例中的Index()和Hello()都是Handle類型的實例。post
func Index(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { fmt.Fprint(w, "Welcome!\n") } func Hello(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { fmt.Fprintf(w, "hello, %s!\n", ps.ByName("name")) }
httprouter.Router類型相似於http包中的ServeMux,它實現了http.Handler接口,因此它是一個http.Handler。它能夠將請求分配給註冊好的handler。code
type Router struct {} func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request)
除此以外,Router提供了很多方法,用來指示如何爲路徑註冊handler。router
func (r *Router) Handle(method, path string, handle Handle) func (r *Router) Handler(method, path string, handler http.Handler) func (r *Router) HandlerFunc(method, path string, handler http.HandlerFunc)
httprouter.Handle()用於爲路徑註冊指定的Handle,而httprouter.Handle對應於http.HandlerFunc,因此是直接將Handle類型的函數綁定到指定路徑上。同時,它還能夠指定http方法:GET, POST, HEAD, PUT, PATCH, DELETE, OPTIONS。htm
這些方法還有對應的各自縮寫:
func (r *Router) DELETE(path string, handle Handle) func (r *Router) GET(path string, handle Handle) func (r *Router) HEAD(path string, handle Handle) func (r *Router) OPTIONS(path string, handle Handle) func (r *Router) PATCH(path string, handle Handle) func (r *Router) POST(path string, handle Handle) func (r *Router) PUT(path string, handle Handle)
例如,Get()等價於route.Handle("GET", path, handle)。
例如上面的示例中,爲兩個路徑註冊了各自的httprouter.Handle函數。
router := httprouter.New() router.GET("/", Index) router.GET("/hello/:name", Hello)
Handler()方法是直接爲指定http方法和路徑註冊http.Handler;HandlerFunc()方法則是直接爲指定http方法和路徑註冊http.HandlerFunc。
type Param struct { Key string Value string } Param is a single URL parameter, consisting of a key and a value. type Params []Param Params is a Param-slice, as returned by the router. The slice is ordered, the first URL parameter is also the first slice value. It is therefore safe to read values by the index. func (ps Params) ByName(name string) string ByName returns the value of the first Param which key matches the given name. If no matching Param is found, an empty string is returned.
Param類型是key/value型的結構,每一個分組捕獲到的值都會保存爲此類型。正如前面的示例中:
router.GET("/hello/:name", Hello)
這裏的:name
就是key,當請求的URL路徑爲/hello/abc
,則key對應的value爲abc。也就是說保存了一個Param實例:
Param{ Key: "name", Value: "abc", }
更多的匹配用法稍後解釋。
Params是Param的slice。也就是說,每一個分組捕獲到的key/value都存放在這個slice中。
ByName(str)方法能夠根據Param的Key檢索已經保存在slice中的Param的Value。正如示例中:
func Hello(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { fmt.Fprintf(w, "hello, %s!\n", ps.ByName("name")) } router.GET("/hello/:name", Hello)
這裏ByName("name")
將檢索保存在slice中,Key="name"的Param,且返回這個Param中的Value。
因爲Params是slice結構,除了ByName()方法能夠檢索key/value,經過slice的方法也能夠直接檢索:
ps[0].Key ps[0].Value
httprouter要爲路徑註冊handler的適合,路徑能夠進行命名捕獲。有兩種命名捕獲的方式:
Syntax Type :name named parameter *name catch-all parameter
其中:name
的捕獲方式是匹配內容直到下一個斜線或者路徑的結尾。例如要爲以下路徑註冊handler:
Path: /blog/: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 /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
再解釋下何時會進行重定向。在Router類型中,第一個字段控制尾隨斜線的重定向操做:
type Router struct { RedirectTrailingSlash bool ... }
若是請求的URL路徑包含或者不包含尾隨斜線時,但在註冊的路徑上包含了或沒有包含"/"的目標上定義了handler,可是會進行301重定向。簡單地說,無論URL是否帶尾隨斜線,只要註冊路徑不存在,但在去掉尾隨斜線或加上尾隨斜線的路徑上定義了handler,就會自動重定向。
例如註冊路徑爲/foo
,請求路徑爲/foo/
,會重定向。
下面還有幾種會重定向的狀況:
註冊路徑:/blog/:category/:post 請求URL路徑:/blog/go/request-routers/ 註冊路徑:/blog/:category 請求URL路徑:/blog/go 註冊路徑:/files/*filepath 請求URL路徑:/files
func (r *Router) Lookup(method, path string) (Handle, Params, bool)
Lookup根據method+path檢索對應的Handle,以及Params,並能夠經過第三個返回值判斷是否會進行重定向。