httprouter
httprouter 是一個高性能、可擴展的HTTP路由,上面我們列舉的net/http
默認路由的不足,都被httprouter 實現,我們先用一個例子,認識下 httprouter 這個強大的 HTTP 路由。
安裝:
go get -u github.com/julienschmidt/httprouter
在這個例子中,首先通過httprouter.New()
生成了一個*Router
路由指針,然后使用GET
方法注冊一個適配/
路徑的Index
函數,最后*Router
作為參數傳給ListenAndServe
函數啟動HTTP服務即可。
package main import ( "log" "net/http" "github.com/julienschmidt/httprouter" ) func Index(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { w.Write([]byte("Index")) } func main() { router := httprouter.New() router.GET("/", Index) log.Fatal(http.ListenAndServe(":8080", router)) }
httprouter 為所有的HTTP Method 提供了快捷的使用方式,只需要調用對應的方法即可。
func (r *Router) GET(path string, handle Handle) { r.Handle("GET", path, handle) } func (r *Router) HEAD(path string, handle Handle) { r.Handle("HEAD", path, handle) } func (r *Router) OPTIONS(path string, handle Handle) { r.Handle("OPTIONS", path, handle) } func (r *Router) POST(path string, handle Handle) { r.Handle("POST", path, handle) } func (r *Router) PUT(path string, handle Handle) { r.Handle("PUT", path, handle) } func (r *Router) PATCH(path string, handle Handle) { r.Handle("PATCH", path, handle) } func (r *Router) DELETE(path string, handle Handle) { r.Handle("DELETE", path, handle) }
現代的API,基本上都是Restful API,httprouter提供的命名參數的支持,可以很方便的幫助我們開發Restful API。比如我們設計的API/user/flysnow
,這這樣一個URL,可以查看flysnow
這個用戶的信息,如果要查看其他用戶的,比如zhangsan
,我們只需要訪問API/user/zhangsan
即可。
URL包括兩種匹配模式:/user/:name精確匹配、/user/*name匹配所有的模式。
package main import ( "github.com/julienschmidt/httprouter" "net/http" "log" "fmt" ) func main() { router:=httprouter.New() router.GET("/MainData", func (w http.ResponseWriter,r *http.Request,_ httprouter.Params) { w.Write([]byte("default get")) }) router.POST("/MainData",func (w http.ResponseWriter,r *http.Request,_ httprouter.Params) { w.Write([]byte("default post")) }) //精確匹配 router.GET("/user/name",func (w http.ResponseWriter,r *http.Request,p httprouter.Params) { w.Write([]byte("user name:"+p.ByName("name"))) }) //匹配所有 router.GET("/employee/*name",func (w http.ResponseWriter,r *http.Request,p httprouter.Params) { w.Write([]byte("employee name:"+p.ByName("name"))) }) http.ListenAndServe(":8081", router) }
Handler處理鏈處理不同二級域名
package main import ( "fmt" "log" "net/http" "github.com/julienschmidt/httprouter" ) type HostMap map[string]http.Handler func (hs HostMap) ServeHTTP(w http.ResponseWriter, r *http.Request) { fmt.Println("222") //根據域名獲取對應的Handler路由,然后調用處理(分發機制) if handler := hs[r.Host]; handler != nil { handler.ServeHTTP(w, r) } else { http.Error(w, "Forbidden", 403) } } func main() { userRouter := httprouter.New() userRouter.GET("/", func(w http.ResponseWriter, r *http.Request, p httprouter.Params) { w.Write([]byte("play")) }) dataRouter := httprouter.New() dataRouter.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { w.Write([]byte("tool")) }) //分別用於處理不同的二級域名 hs := make(HostMap) hs["user.localhost:12345"] = userRouter hs["data.localhost:12345"] = dataRouter log.Fatal(http.ListenAndServe(":12345", hs)) }
httprouter提供了很方便的靜態文件服務,可以把一個目錄托管在服務器上,以供訪問。
router.ServeFiles("/static/*filepath",http.Dir("./"))
使用ServeFiles
需要注意的是,第一個參數路徑,必須要以/*filepath
,因為要獲取我們要訪問的路徑信息。
func (r *Router) ServeFiles(path string, root http.FileSystem) { if len(path) < 10 || path[len(path)-10:] != "/*filepath" { panic("path must end with /*filepath in path '" + path + "'") } fileServer := http.FileServer(root) r.GET(path, func(w http.ResponseWriter, req *http.Request, ps Params) { req.URL.Path = ps.ByName("filepath") fileServer.ServeHTTP(w, req) }) }
例子:
package main import ( "log" "net/http" "github.com/julienschmidt/httprouter" ) func main() { router := httprouter.New() //訪問靜態文件 router.ServeFiles("/static/*filepath", http.Dir("./files")) log.Fatal(http.ListenAndServe(":8080", router)) }
httprouter 異常捕獲,httprouter允許使用者,設置PanicHandler
用於處理HTTP請求中發生的panic。
package main import ( "fmt" "log" "net/http" "github.com/julienschmidt/httprouter" ) func Index(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { panic("error") } func main() { router := httprouter.New() router.GET("/", Index) //捕獲異常 router.PanicHandler = func(w http.ResponseWriter, r *http.Request, v interface{}) { w.WriteHeader(http.StatusInternalServerError) fmt.Fprintf(w, "error:%s", v) } log.Fatal(http.ListenAndServe(":8080", router)) }
httprouter還有不少有用的小功能,比如對404進行處理,我們通過設置Router.NotFound
來實現,我們看看Router
這個結構體的配置,可以發現更多有用的功能。
type Router struct { //是否通過重定向,給路徑自定加斜杠 RedirectTrailingSlash bool //是否通過重定向,自動修復路徑,比如雙斜杠等自動修復為單斜杠 RedirectFixedPath bool //是否檢測當前請求的方法被允許 HandleMethodNotAllowed bool //是否自定答復OPTION請求 HandleOPTIONS bool //404默認處理 NotFound http.Handler //不被允許的方法默認處理 MethodNotAllowed http.Handler //異常統一處理 PanicHandler func(http.ResponseWriter, *http.Request, interface{}) }