你應該如何去選擇 Go router?

我是一隻可愛的土撥鼠,專注於分享 Go 職場、招聘和求職,解 Gopher 之憂!歡迎關注我。

歡迎大家加入 Go 招聘交流羣,來這裏找志同道合的小夥伴!跟土撥鼠們一起交流學習。

目錄


平時你是不是也糾結該用哪個 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 個受歡迎的案例,並評估出了一個最佳選項的名單列表,以及一個流程圖,可以用來幫助指導你作出選擇。

在我們開始之前,有幾個關於術語的注意事項:

注意: 從軟件工程的角度來看,路由衝突並不是件好事。它可能就是 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響應碼,而且允許爲404405響應設置自定義的 handler。

它不支持基於主機的路由、自定義路由規則或 regexp 路由模式。需要注意的是,httprouter 也不允許有衝突的路由,比如/post/create/post/:id。這在客觀上是一件好事,因爲它有助於避免 bug,但如果您需要使用衝突的路由 (例如與現有系統使用的路由保持一致) ,則可能會出現問題。

httprouter的一個缺點是,API 和文檔有點混亂。這個包是在 Go 1.7 中引入請求上下文之前就已發佈,很多當前的 API 仍然存在,以支持這些舊版本的 Go。現在,你可以使用常規的http.Handlerhttp.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 那麼重要。相比之下,httproutergorilla/mux 在這段時間裏並沒有做出任何突破性的改變。

值得注意的是,在過去的 6 年中,chi已經有 5 個主要的版本增量 -- 其中大部分都包括重大變化。歷史不一定是未來的預測,但確實表明,與這個入圍名單上的其他一些路由器相比,向後兼容和不做破壞性的修改對chi來說不是那麼重要。相比之下,httproutergorilla/mux在這段時間內沒有做任何破壞性的改動。

gorilla/mux

gorilla/mux包可能是最著名的 Go router,這是有原因的。它包括了各種功能,包括支持基於方法的路由、動態 URL、regexp 路由模式和基於主機的路由。重要的是,它是這個入圍名單上唯一支持自定義路由規則和路由 "反轉" 的 router(就像你在 Django、Rails 或 Laravel 中看到的那樣)。它還允許你爲 404 和 405 響應設置自定義 handler。

它的缺點基本上和 chi 一樣ーー它不會像 httprouter 那樣自動處理 OPTIONS 請求,也不會在 405 響應中包含 Allow header。同樣,和 chi 一樣,它也允許相互衝突的路由,會按聲明的順序進行匹配。

鑑於chigorilla/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 來更新代碼庫。

7Zu7U2

參考資料

[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