【Golang源码分析】Go Web常用程序包gorilla/mux的使用与源码简析
目錄【閱讀時(shí)間:約10分鐘】
- 一.概述
- 二.對(duì)比: gorilla/mux與net/http DefaultServeMux
- 三.簡(jiǎn)單使用
- 四.源碼簡(jiǎn)析
- 1.NewRouter函數(shù)
- 2.HandleFunc函數(shù)
- 設(shè)置路由的HTTP方法
- 設(shè)置路由的域名
- 限制HTTP 方案
- 設(shè)置路徑前綴和子路由
- 3.PathPrefix函數(shù)
- 五.References
一.概述
gorilla/mux程序包,是一個(gè)強(qiáng)大的url路由和調(diào)度器,它具有小巧但是穩(wěn)定高效的特性。
不僅可以支持正則路由,還可以按照Method、header、host等信息匹配,可以從我們?cè)O(shè)定的路由表達(dá)式中提取出參數(shù)方便上層應(yīng)用,而且完全兼容http.ServerMux。
二.對(duì)比: gorilla/mux與net/http DefaultServeMux
Go 官方標(biāo)準(zhǔn)庫(kù) net/http 自帶的 DefaultServeMux 底層實(shí)現(xiàn),通過(guò) DefaultServeMux 提供的路由處理器雖然簡(jiǎn)單易上手,但是存在很多不足,比如:
- 不支持參數(shù)設(shè)定,例如
/user/:uid這種泛類型匹配; - 對(duì) REST 風(fēng)格接口支持不友好,無(wú)法限制訪問(wèn)路由的方法;
- 對(duì)于擁有很多路由規(guī)則的應(yīng)用,編寫大量路由規(guī)則非常繁瑣。
為此,我們可以使用第三方庫(kù) gorilla/mux 提供的更加強(qiáng)大的路由處理器(mux 代表 HTTP request multiplexer,即 HTTP 請(qǐng)求多路復(fù)用器),和 http.ServeMux 實(shí)現(xiàn)原理一樣,gorilla/mux 提供的路由器實(shí)現(xiàn)類 mux.Router 也會(huì)匹配用戶請(qǐng)求與系統(tǒng)注冊(cè)的路由規(guī)則,然后將用戶請(qǐng)求轉(zhuǎn)發(fā)過(guò)去。
mux.Router 主要具備以下特性:
- 實(shí)現(xiàn)了
http.Handler接口,所以和http.ServeMux完全兼容; - 可以基于 URL 主機(jī)、路徑、前綴、scheme、請(qǐng)求頭、請(qǐng)求參數(shù)、請(qǐng)求方法進(jìn)行路由匹配;
- URL 主機(jī)、路徑、查詢字符串支持可選的正則匹配;
- 支持構(gòu)建或反轉(zhuǎn)已注冊(cè)的 URL 主機(jī),以便維護(hù)對(duì)資源的引用;
- 支持路由嵌套(類似 Laravel 中的路由分組),以便不同路由可以共享通用條件,比如主機(jī)、路徑前綴等。
三.簡(jiǎn)單使用
安裝程序包:
go get -u github.com/gorilla/mux
樣例①:
基于Golang的簡(jiǎn)單web服務(wù)程序開(kāi)發(fā)——CloudGo
主要的相關(guān)函數(shù)為NewServer函數(shù)與initRoutes函數(shù):
// NewServer configures and returns a Server.
func NewServer() *negroni.Negroni {formatter := render.New(render.Options{Directory: "templates",Extensions: []string{".html"},IndentJSON: true,})n := negroni.Classic()mx := mux.NewRouter()initRoutes(mx, formatter)n.UseHandler(mx)return n
}func initRoutes(mx *mux.Router, formatter *render.Render) {webRoot := os.Getenv("WEBROOT")if len(webRoot) == 0 {if root, err := os.Getwd(); err != nil {panic("Could not retrive working directory")} else {webRoot = root//fmt.Println(root)}}mx.HandleFunc("/api/test", apiTestHandler(formatter)).Methods("GET")mx.HandleFunc("/", homeHandler(formatter)).Methods("GET")mx.HandleFunc("/user", userHandler).Methods("POST")mx.PathPrefix("/").Handler(http.FileServer(http.Dir(webRoot + "/assets/")))
}
樣例②:
package mainimport ("fmt""github.com/gorilla/mux""log""net/http"
)func sayHelloWorld(w http.ResponseWriter, r *http.Request) {w.WriteHeader(http.StatusOK) // 設(shè)置響應(yīng)狀態(tài)碼為 200fmt.Fprintf(w, "Hello, World!") // 發(fā)送響應(yīng)到客戶端
}func main() {r := mux.NewRouter()r.HandleFunc("/hello", sayHelloWorld)log.Fatal(http.ListenAndServe(":8080", r))
}
在 main 函數(shù)中的第一行顯式初始化了 mux.Router 作為路由器,然后在這個(gè)路由器中注冊(cè)路由規(guī)則,最后將這個(gè)路由器傳入 http.ListenAndServe 方法,整個(gè)調(diào)用過(guò)程和之前并無(wú)二致,因?yàn)槲覀兦懊嬲f(shuō)了,mux.Router 也實(shí)現(xiàn)了 Handler 接口。
運(yùn)行這段代碼,在瀏覽器訪問(wèn) http://localhost:8080/hello,即可渲染出如下結(jié)果:
Hello, World!
四.源碼簡(jiǎn)析
gorilla/mux源碼可分為context、mux、regex、route四個(gè)部分,在CloudGo項(xiàng)目開(kāi)發(fā)過(guò)程中,我主要使用了NewRouter、HandleFunc和PathPrefix這三個(gè)函數(shù)。下面對(duì)這三個(gè)函數(shù)進(jìn)行分析:
1.NewRouter函數(shù)
Router是一個(gè)結(jié)構(gòu)體,如下:
type Router struct {// Configurable Handler to be used when no route matches.NotFoundHandler http.Handler// Configurable Handler to be used when the request method does not match the route.MethodNotAllowedHandler http.Handler// Parent route, if this is a subrouter.parent parentRoute// Routes to be matched, in order.routes []*Route// Routes by name for URL building.namedRoutes map[string]*Route// See Router.StrictSlash(). This defines the flag for new routes.strictSlash bool// See Router.SkipClean(). This defines the flag for new routes.skipClean bool// If true, do not clear the request context after handling the request.// This has no effect when go1.7+ is used, since the context is stored// on the request itself.KeepContext bool// see Router.UseEncodedPath(). This defines a flag for all routes.useEncodedPath bool
}
調(diào)用NewRouter函數(shù)可用來(lái)實(shí)例化一個(gè)Router:
// NewRouter returns a new router instance.
func NewRouter() *Router {return &Router{namedRoutes: make(map[string]*Route), KeepContext: false}
}
這里可以看見(jiàn),它開(kāi)辟了一個(gè)裝Route指針的map,然后默認(rèn)該Router的KeepContext為false,意思是在請(qǐng)求被處理完之后清除該請(qǐng)求的上下文。
2.HandleFunc函數(shù)
// HandleFunc registers a new route with a matcher for the URL path.
// See Route.Path() and Route.HandlerFunc().
func (r *Router) HandleFunc(path string, f func(http.ResponseWriter,*http.Request)) *Route {return r.NewRoute().Path(path).HandlerFunc(f)
}
若只觀察HandleFunc函數(shù),會(huì)發(fā)現(xiàn)其代碼只有幾行,其主要功能是使用URL的匹配器注冊(cè)新路由。
gorilla/mux的HandleFunc函數(shù)功能很強(qiáng)大,主要有以下功能:
設(shè)置路由的HTTP方法
限制路由處理器只處理指定的HTTP方法的請(qǐng)求:
router.HandleFunc("/books/{title}", CreateBook).Methods("POST")
router.HandleFunc("/books/{title}", ReadBook).Methods("GET")
router.HandleFunc("/books/{title}", UpdateBook).Methods("PUT")
router.HandleFunc("/books/{title}", DeleteBook).Methods("DELETE")
上面的就是一組可以響應(yīng)具體HTTP方法的RESTful風(fēng)格的接口的路由。
設(shè)置路由的域名
限制路由處理器只處理訪問(wèn)指定域名加路由的請(qǐng)求:
router.HandleFunc("/books/{title}", BookHandler).Host("www.mybookstore.com")
限制HTTP 方案
將請(qǐng)求處理程序可響應(yīng)的HTTP方案限制為http或者https。
router.HandleFunc("/secure", SecureHandler).Schemes("https")
router.HandleFunc("/insecure", InsecureHandler).Schemes("http")
設(shè)置路徑前綴和子路由
bookrouter := router.PathPrefix("/books").Subrouter()
bookrouter.HandleFunc("/", AllBooks)
bookrouter.HandleFunc("/{title}", GetBook)
3.PathPrefix函數(shù)
// PathPrefix registers a new route with a matcher for the URL path prefix.
// See Route.PathPrefix().
func (r *Router) PathPrefix(tpl string) *Route {return r.NewRoute().PathPrefix(tpl)
}
PathPrefix函數(shù)源碼也只有幾行,它的功能只是簡(jiǎn)單地增加URL的前綴,通常結(jié)合HandleFunc函數(shù)和Handler函數(shù)來(lái)使用。
五.References
- 基于 gorilla/mux 包實(shí)現(xiàn)路由定義和請(qǐng)求分發(fā):基本使用
- gorilla/mux類庫(kù)解析
- Gorilla源碼分析之gorilla/mux源碼分析
- 從一個(gè)例子分析gorilla/mux源碼
- gorilla/mux官方GitHub
總結(jié)
以上是生活随笔為你收集整理的【Golang源码分析】Go Web常用程序包gorilla/mux的使用与源码简析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 基于Golang的简单web服务程序开发
- 下一篇: 【CentOS】利用Kubeadm部署K