你應該如何去選擇 Go router?
我是一隻可愛的土撥鼠,專注於分享 Go 職場、招聘和求職,解 Gopher 之憂!歡迎關注我。
歡迎大家加入 Go 招聘交流羣,來這裏找志同道合的小夥伴!跟土撥鼠們一起交流學習。
目錄
-
入圍的 router
-
http.ServeMux
-
julienschmidt/httprouter
-
go-chi/chi
-
gorilla/mux
-
榮譽提名 bmizerany/pat 和 matryer/way
-
流程圖
-
其他 router
平時你是不是也糾結該用哪個 router 呢?土撥鼠今天帶來一篇 router 比較的文章,土撥鼠翻譯這篇文章也收穫了很多(瞭解 router 的特性、優秀的代碼欣賞等),同時希望能給大家在選擇 router 的時候提供一些參考意見。本文主要翻譯自 https://www.alexedwards.net/blog/which-go-router-should-i-use。由於土撥鼠翻譯水平有限,不足之處煩請指出。另外作者也出書了。書名《Let’s Go》[1] 和 《Let’s Go Further》[2]。主要介紹瞭如何去使用 Go 構建專業的生產級 web 應用程序和 api。感興趣的同學可以看看。
本文外鏈較多,想要更好體驗的話可以閱讀原文跳轉到 Go 招聘網站上進行閱讀。
當你開始使用 Go 構建 web 應用程序時,你可能會問的第一個問題就是 “我應該使用哪個 router?”.
這也不是一個容易回答的問題。可能有超過 100 種不同的 router[3],它們都有不同的 api、特性和行爲。因此,在這篇博客文章中,評估了 30 個受歡迎的案例,並評估出了一個最佳選項的名單列表,以及一個流程圖,可以用來幫助指導你作出選擇。
在我們開始之前,有幾個關於術語的注意事項:
-
所說的支持基於方法的路由是指可以很容易地根據請求方法 (
GET
、POST
等) 將不同的 HTTP 請求分發給不同的 handler。 -
通過支持 URL 路徑中的變量,這裏的意思是 router 可以很容易地聲明像
/movies/{ id }
這樣的路由,其中{ id }
是 URL 路徑中的動態變量值。 -
通過支持正則 regexp 路由模式,意思是 router 可以很容易地聲明像
/movies/{[ a-z-] + }
這樣的路由,其中[ a-z-] +
是 URL 路徑中必需的 regexp 匹配。 -
通過支持基於主機的路由,意思是,router 可以很容易地根據 URL 主機 (如
www.example. com
) 而不僅僅是 URL 路徑向不同的 handler 發送 HTTP 請求。 -
通過支持自定義路由規則,意思是 router 可以很容易地爲路由請求添加自定義規則 (例如根據 IP 地址或 header 中
Authorization
的值路由到不同的 handler)。 -
這裏所說的衝突路由指的是當註冊兩個 (或更多) 路由模式時,它們可能匹配相同的請求 URL 路徑。例如,如果您註冊了路由
/blog/{ slug }
和/blog/new
,那麼帶有路徑/blog/new
的 HTTP 請求將會匹配這兩個路由。
注意: 從軟件工程的角度來看,路由衝突並不是件好事。它可能就是 bug 和混亂的來源,我們應該在應用程序中儘量避免它們。
入圍的 router
有四種不同的 router 進入了入圍名單。它們是 http.ServeMux
[4], julienschmidt/httprouter
[5], go-chi/chi
[6] 和 gorilla/mux
[7]. 。這四個 router 都經過了充分的測試,文檔也寫得很友好,並且到現在還在積極地維護中。它們 (大多數) 有穩定的 api,並且與 http.Handler
, http.HandlerFunc
兼容。標準庫的中間件模式 [8]。
在性能方面,所有四個 router 對於 (幾乎) 每個應用程序來說都足夠快,建議你可以根據需要的特定功能而不是性能來選擇它們。我個人曾不同時間在生產應用程序中使用過這四個 router,並且對它們感到非常滿意。
http.ServeMux
我首先要說的是,如果你可以使用 http.ServeMux
[9],就近可能應該使用它。
作爲 Go 標準庫的一部分,它經過了嚴格的實戰測試並有詳細的文檔記錄。使用它意味着不需要導入任何第三方依賴項,而且大多數其他 Go 開發人員也會熟悉它的工作原理。Go 1 兼容性承諾還意味着應該能夠http.ServeMux
長期依靠相同的方式工作。所有這些在應用程序維護方面都是很大的積極因素。
與其他大多數 router 不同,它還支持基於主機的路由,傳入請求的 url 會自動清理,並且它匹配路由的方式也很聰明: 較長的路由模式總是優先於較短的路由。這是一個很好的副作用,您可以以任何順序註冊,並且它不會改變應用程序的行爲。
兩個主要限制http.ServeMux
的是它不支持基於方法的路由或 URL 路徑中的變量。但是缺乏對基於方法的路由的支持並不總是避免使用它的好理由——可以使用下面這樣的代碼解決:
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/", index)
err := http.ListenAndServe(":3000", mux)
log.Fatal(err)
}
func index(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/" {
http.NotFound(w, r)
return
}
// Common code for all requests can go here...
switch r.Method {
case http.MethodGet:
// Handle the GET request...
case http.MethodPost:
// Handle the POST request...
case http.MethodOptions:
w.Header().Set("Allow", "GET, POST, OPTIONS")
w.WriteHeader(http.StatusNoContent)
default:
w.Header().Set("Allow", "GET, POST, OPTIONS")
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
}
}
在上面幾行代碼中就可以實現了基於方法的路由,以及定製的 404 和 405 響應和對 OPTIONS
請求的支持。
隨着時間的推移,我逐漸意識到這http.ServeMux
有很多優秀的地方,而且在很多情況下已經足夠了。事實上,我唯一建議不要使用它的時候是需要支持 URL 路徑中的變量或自定義路由規則。在這些情況下,嘗試使用http.ServeMux
可能會有點麻煩,我認爲選擇第三方 router 通常會更好。
julienschmidt/httprouter
我認爲這 julienschmidt/httprouter
[10] 的行爲和對 HTTP 規範的合規性方面,是任何第三方 router 最接近 “完美” 的。它支持基於方法的路由和動態 URL。它還自動處理OPTIONS
請求並正確地發送405
響應碼,而且允許爲404
和 405
響應設置自定義的 handler。
它不支持基於主機的路由、自定義路由規則或 regexp 路由模式。需要注意的是,httprouter
也不允許有衝突的路由,比如/post/create
和 /post/:id
。這在客觀上是一件好事,因爲它有助於避免 bug,但如果您需要使用衝突的路由 (例如與現有系統使用的路由保持一致) ,則可能會出現問題。
httprouter
的一個缺點是,API 和文檔有點混亂。這個包是在 Go 1.7 中引入請求上下文之前就已發佈,很多當前的 API 仍然存在,以支持這些舊版本的 Go。現在,你可以使用常規的http.Handler
和http.HandlerFunc
簽名來寫你的 handler,你所需要的是要註冊router.Handler()
和router.HandlerFunc()
方法。例如:
func main() {
router := httprouter.New()
router.HandlerFunc("GET", "/", indexGet)
router.HandlerFunc("POST", "/", indexPost)
err := http.ListenAndServe(":3000", mux)
log.Fatal(err)
}
func indexGet(w http.ResponseWriter, r *http.Request) {
// Handle the GET request...
}
func indexPost(w http.ResponseWriter, r *http.Request) {
// Handle the POST request...
}
go-chi/chi
go-chi/chi
[11] 包支持基於方法的路由、 URL 路徑中的變量和 regexp 路由模式。像 · 一樣,它也允許你爲 404 和 405 個響應設置自定義 handler。
但我最喜歡的是,在chi
中可以創建使用特定中間件的路由 "組",比如下面的代碼片段。這對於有很多中間件和路由需要管理的大型應用來說非常有用。
r := chi.NewRouter()
// Middleware used on all routes
r.Use(exampleMiddlewareOne)
r.Use(exampleMiddlewareTwo)
r.Get("/one", exampleHandlerOne)
r.Group(func(r chi.Router) {
// Middleware only used in this route group
r.Use(exampleMiddlewareThree)
r.Get("/two", exampleHandlerTwo)
})
值得注意的是,chi
允許衝突的路由,路由是按照聲明的順序進行匹配的。
chi
的兩個缺點是它不能自動處理 OPTIONS 請求,而且它不能在 405 響應中設置Allow
header。如果你正在建立一個網絡應用程序或私人 API,那麼這些東西可能不是一個大問題 -- 但如果你正在建立一個公共 API,這就是需要注意的事情了。和httprouter
一樣,它也不支持基於主機的路由.
值得注意的是,在過去的 6 年裏,chi
已經有了 5 個主要的版本增量,其中大部分都包含了破壞性的變化。歷史並不一定能預測未來,但確實表明,對於 chi
來說,向後兼容性和不進行性更改並不像這個短名單上的其他一些 router 那麼重要。相比之下,httprouter
和 gorilla/mux
在這段時間裏並沒有做出任何突破性的改變。
值得注意的是,在過去的 6 年中,chi
已經有 5 個主要的版本增量 -- 其中大部分都包括重大變化。歷史不一定是未來的預測,但確實表明,與這個入圍名單上的其他一些路由器相比,向後兼容和不做破壞性的修改對chi
來說不是那麼重要。相比之下,httprouter
和gorilla/mux
在這段時間內沒有做任何破壞性的改動。
gorilla/mux
gorilla/mux
包可能是最著名的 Go router,這是有原因的。它包括了各種功能,包括支持基於方法的路由、動態 URL、regexp 路由模式和基於主機的路由。重要的是,它是這個入圍名單上唯一支持自定義路由規則和路由 "反轉" 的 router(就像你在 Django、Rails 或 Laravel 中看到的那樣)。它還允許你爲 404 和 405 響應設置自定義 handler。
它的缺點基本上和 chi
一樣ーー它不會像 httprouter
那樣自動處理 OPTIONS
請求,也不會在 405 響應中包含 Allow
header。同樣,和 chi
一樣,它也允許相互衝突的路由,會按聲明的順序進行匹配。
鑑於chi
和gorilla/mux
的缺點很相似,在兩者之間你可以直接選擇:如果你需要支持自定義路由規則、基於主機的路由或路由 "反轉",選擇gorilla/mux
。如果你不需要這些 "高級" 功能,那麼最好選擇chi
,因爲它有很好的管理中間件的功能,特別是如果你正在構建一個大型應用。
榮譽提名 bmizerany/pat 和 matryer/way
我認爲值得一提的另外兩個 router 是 bmizerany/pat
[12] 和 matryer/way
[13]。我對這兩個都情有獨鍾,因爲它們都是故意簡單化的。它們擁有很小的 api 和非常清晰易懂的代碼,這使得我們可以很容易準確地掌握 router 在幕後是如何工作的。尤其是matryer/way
背後的代碼,非常值得一讀。
雖然它們的功能不如入圍名單中的其他 router,但我認爲它們的簡單性使它們很適合用於教程(尤其是針對入門 gopher 的教程),如果你想建立自己的自定義 router,可以把它們作爲一個起點 / 靈感。
流程圖
考慮到各種利弊和支持的功能,這個流程圖應該可以幫助你在四個入圍的 router 之間做出選擇。
其他 router
下面列出了評估的其他 router,以及一個簡短的說明,解釋了爲什麼它們沒有進入名單中。
注意: 使用這個問題 “代碼庫是否包含 go.mod 文件?” 作爲一個代理來測量一個代碼庫當前是否在維護。這似乎是合理的——如果維護者仍然參與 Go 生態並關注代碼,他們應該會在過去幾年的某個時候使用 modules 來更新代碼庫。
參考資料
[1] 《Let’s Go》: https://lets-go.alexedwards.net/
[2] 《Let’s Go Further》: https://lets-go-further.alexedwards.net/
[3] 100 種不同的 router: https://github.com/search?l=Go&p=5&q=http+router&type=Repositories
[4] http.ServeMux
: https://pkg.go.dev/net/http#ServeMux
[5] julienschmidt/httprouter
: https://github.com/julienschmidt/httprouter
[6] go-chi/chi
: https://github.com/go-chi/chi
[7] gorilla/mux
: https://github.com/gorilla/mux
[8] 標準庫的中間件模式: https://www.alexedwards.net/blog/making-and-using-middleware
[9] http.ServeMux
: https://pkg.go.dev/net/http#ServeMux
[10] julienschmidt/httprouter
: https://github.com/julienschmidt/httprouter
[11] go-chi/chi
: https://github.com/go-chi/chi
[12] bmizerany/pat
: https://github.com/bmizerany/pat
[13] matryer/way
: https://github.com/matryer/way
[14] celrenheit/lion: https://github.com/celrenheit/lion
[15] claygod/Bxog: https://github.com/claygod/Bxog
[16] clevergo/clevergo: https://github.com/clevergo/clevergo
[17] dimfeld/httptreemux: https://github.com/dimfeld/httptreemux
[18] donutloop/mux: https://github.com/donutloop/mux
[19] gernest/alien: https://github.com/gernest/alien
[20] go-ozzo/ozzo-routing: https://github.com/go-ozzo/ozzo-routing
[21] go-playground/lars: https://github.com/go-playground/lars
[22] go-zoo/bone: https://github.com/go-zoo/bone
[23] go101/tinyrouter: https://github.com/go101/tinyrouter
[24] gocraft/web: https://github.com/gocraft/web
[25] goji/goji: https://github.com/goji/goji
[26] goroute/route: https://github.com/goroute/route
[27] gowww/router: https://github.com/gowww/router
[28] GuilhermeCaruso/bellt: https://github.com/GuilhermeCaruso/bellt
[29] husobee/vestigo: https://github.com/husobee/vestigo
[30] naoina/denco: https://github.com/naoina/denco
[31] nbari/violetear: https://github.com/nbari/violetear
[32] nbio/hitch: https://github.com/nbio/hitch
[33] nissy/bon: https://github.com/nissy/bon
[34] razonyang/fastrouter: https://github.com/razonyang/fastrouter
[35] rs/xmux: https://github.com/rs/xmux
[36] takama/router: https://github.com/takama/router
[37] vardius/gorouter: https://github.com/vardius/gorouter
[38] VividCortex/siesta: https://github.com/VividCortex/siesta
[39] xujiajun/gorouter: https://github.com/xujiajun/gorouter
歡迎關注 Go 招聘公衆號,獲取 Go 專題、大廠內推、面經、簡歷、股文等相關資料可回覆和點擊導航查閱。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/RnRkS8stazKlMN6aFAdtwA