Go 語言 Web 編程系列(四)—— 基於 gorilla/mux 包實現路由定義:基本使用篇
- 2019 年 12 月 31 日
- 筆記
1、功能簡介
前面我們介紹了 Go 官方標準庫 net/http
自帶的 DefaultServeMux
底層實現,通過 DefaultServeMux
提供的路由處理器雖然簡單易上手,但是存在很多不足,比如:
- 不支援參數設定,例如
/user/:uid
這種泛類型匹配; - 對 REST 風格介面支援不友好,無法限制訪問路由的方法;
- 對於擁有很多路由規則的應用,編寫大量路由規則非常繁瑣。
為此,我們可以使用第三方庫 gorilla/mux
提供的更加強大的路由處理器(mux
代表 HTTP request multiplexer
,即 HTTP 請求多路復用器),和 http.ServeMux
實現原理一樣,gorilla/mux
提供的路由器實現類 mux.Router
也會匹配用戶請求與系統註冊的路由規則,然後將用戶請求轉發過去。
mux.Router
主要具備以下特性:
- 實現了
http.Handler
介面,所以和http.ServeMux
完全兼容; - 可以基於 URL 主機、路徑、前綴、scheme、請求頭、請求參數、請求方法進行路由匹配;
- URL 主機、路徑、查詢字元串支援可選的正則匹配;
- 支援構建或反轉已註冊的 URL 主機,以便維護對資源的引用;
- 支援路由嵌套(類似 Laravel 中的路由分組),以便不同路由可以共享通用條件,比如主機、路徑前綴等。
2、使用入門
開始使用 mux.Router
之前,需要安裝這個擴展包:
go get -u github.com/gorilla/mux
然後在我們可以這樣實現創建第一個Web應用中演示的註冊路由:
package main import ( "fmt" "github.com/gorilla/mux" "log" "net/http" ) func sayHelloWorld(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) // 設置響應狀態碼為 200 fmt.Fprintf(w, "Hello, World!") // 發送響應到客戶端 } func main() { r := mux.NewRouter() r.HandleFunc("/hello", sayHelloWorld) log.Fatal(http.ListenAndServe(":8080", r)) }
在 main
函數中的第一行顯式初始化了 mux.Router
作為路由器,然後在這個路由器中註冊路由規則,最後將這個路由器傳入 http.ListenAndServe
方法,整個調用過程和之前並無二致,因為我們前面說了,mux.Router
也實現了 Handler
介面。
運行這段程式碼,在瀏覽器訪問 http://localhost:8080/hello
,即可渲染出如下結果:
Hello, World!
3、路由參數
現在,我們想要在路由定義中設置路由參數,例如 /hello/world
、/hello/學院君
,這可以通過如下方式來實現:
r.HandleFunc("/hello/{name}", sayHelloWorld)
你甚至還可以通過正則表達式限制參數字元:
r.HandleFunc("/hello/{name:[a-z]+}", sayHelloWorld)
以上規則表示路由參數只能是小寫字母,不支援其它字元。
相應地,在閉包處理函數中,我們需要這樣解析路由參數:
func sayHelloWorld(w http.ResponseWriter, r *http.Request) { params := mux.Vars(r) w.WriteHeader(http.StatusOK) // 設置響應狀態碼為 200 fmt.Fprintf(w, "Hello, %s!", params["name"]) // 發送響應到客戶端 }
重啟伺服器,這次,我們可以通過 http://localhost:8080/hello/xueyuanjun
這種方式請求路由了:
Hello, xueyuanjun!
如果參數中包含中文,則返回 404 響應,表示路由匹配失敗:

4、自定義處理器
和 http.ServeMux
一樣,在 mux.Router
中,還可以將請求轉發到自定義的處理器類,而不是閉包函數:
package main import ( "fmt" "github.com/gorilla/mux" "log" "net/http" ) func sayHelloWorld(w http.ResponseWriter, r *http.Request) { params := mux.Vars(r) w.WriteHeader(http.StatusOK) // 設置響應狀態碼為 200 fmt.Fprintf(w, "Hello, %s!", params["name"]) // 發送響應到客戶端 } type HelloWorldHandler struct {} func (handler *HelloWorldHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { params := mux.Vars(r) w.WriteHeader(http.StatusOK) // 設置響應狀態碼為 200 fmt.Fprintf(w, "你好, %s!", params["name"]) // 發送響應到客戶端 } func main() { r := mux.NewRouter() r.HandleFunc("/hello/{name:[a-z]+}", sayHelloWorld) r.Handle("/zh/hello/{name}", &HelloWorldHandler{}) log.Fatal(http.ListenAndServe(":8080", r)) }
和上篇教程介紹的自定義路由處理器一樣,這裡自定義的 HelloWorldHandler
也要實現 Handler
介面聲明的 ServeHTTP
方法,調用方式和之前一樣,只是需要通過 r.Handle
方法,因為第二個參數傳入的是處理器實例,而不是閉包函數。
重啟伺服器,我們就可以訪問如下 HTTP 路由了:

以上,就是 gorilla/mux 擴展包提供的路由器 mux.Router
的基本使用,下篇教程,我們繼續介紹它的更多路由匹配功能,包括限定主機、請求方法、scheme、路徑前綴、請求頭、查詢字元串等,通過 mux.Router
,我們甚至可以構建出比 Laravel 路由還要強大的路由匹配規則。