你应该如何去选择Go router?

336次阅读  |  发布于3年以前

目录

平时你是不是也纠结该用哪个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来更新代码库。

Repository Notes
celrenheit/lion[14] 目前尚未维护
claygod/Bxog[15] 目前尚未维护
clevergo/clevergo[16] 使用自定义handler签名(不是 http.Handler 或 http.HandlerFunc)。
dimfeld/httptreemux[17] 不完全支持 http.Handler。需要中间件来设置自定义 404/405 handler。
donutloop/mux[18] 目前尚未维护
gernest/alien[19] 目前尚未维护
go-ozzo/ozzo-routing[20] 使用自定义handler签名(不是 http.Handler 或 http.HandlerFunc)。
go-playground/lars[21] 目前尚未维护
go-zoo/bone[22] 很好,但与 chi 有类似的用例(提供的更多)。但是测试不够完整的。
go101/tinyrouter[23] 详细的路由说明。不会自动发送 405 响应。
gocraft/web[24] 目前尚未维护
goji/goji[25] 稍微有点不寻常但具备灵活的 API,支持自定义匹配程序。需要中间件来设置自定义 404/405 handler。也很好,但我认为 gorilla/mux 提供了类似的功能并且更易于使用。
goroute/route[26] 使用自定义handler签名(不是 http.Handler 或 http.HandlerFunc)。
gowww/router[27] 很好,但是有类似 chi 的用例(提供更多)。没有办法设置自定义405handler。
GuilhermeCaruso/bellt[28] 无法设置自定义404或405 handlers.
husobee/vestigo[29] 目前尚未维护 只支持http.HandlerFunc.
naoina/denco[30] 目前尚未维护
nbari/violetear[31] 很好,但是和 chi 有类似的用例(它提供更多)。wrap http.ResponseWriter 用自己的定制类型,这在某些情况下可能会出现问题。
nbio/hitch[32] 缺乏文档
nissy/bon[33] 目前尚未维护
razonyang/fastrouter[34] 目前尚未维护
rs/xmux[35] 目前尚未维护 使用自定义handler签名(不是 http.Handler 或 http.HandlerFunc)。
takama/router[36] 目前尚未维护
vardius/gorouter[37] 很好,但是和 chi 有类似的用例(它提供更多)。5年的4个主要版本表明这个 API 可能并不是很可靠。
VividCortex/siesta[38] 很好,但是有类似 chi 的用例(提供更多)。没有办法设置自定义405handler。
xujiajun/gorouter[39] 目前尚未维护

参考资料

[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

Copyright© 2013-2020

All Rights Reserved 京ICP备2023019179号-8