译者 | 刘汪洋
审校 | 重楼
Go 的标准库中包含一个稳定且成熟的 HTTP 服务器 。然而,内置的请求路由器http.ServeMux 功能较为简洁,因此你常常需要自己编写路由代码 。
文章插图
其主要短板是,它并未支持 HTTP 方法的匹配(如GET和POST的区别),同时也无法持/users/{user}/settings这种类型的通配符路径 。然而,这两个功能几乎是所有 REST 风格的 API 服务器所必需的 。
当然,你可以选择自行实现这些功能 。在我以前的一篇文章 Go 中不同的 HTTP 路由方法中,提到过有一些优秀的第三方包可以实现更高级的路由功能,并且只需 约 30 行代码 就能够在不借助任何第三方库的情况下实现类似的功能 。
但是,未来可能不再需要这些替代方案和第三方包 。现在有一个 活跃的提案 - 还包括一个旨在改进 ServeMux 参考实现 ,使其能够匹配 HTTP 方法和通配符路径 。
google 的 Go 团队成员 Jonathan Amsterdam 主导了这个提案以及之前的 讨论 。Jonathan 曾成功提出将结构化日志添加到标准库的提案 - Go 1.21 将包含他的log/slog包(预计 2023 年 8 月发布) 。
现状与变革在目前的情况下,如果想将 GET 请求匹配到 /users/{user}/settings,你需要编写以下的样板代码(尽管在实践中你可能会使用第三方库):
mux.HandleFunc("/users/", func(w http.ResponseWriter, r *http.Request) {if r.Method != "GET" {http.Error(w, "method not allowed", http.StatusMethodNotAllowed)return}remAInder := r.URL.Path[len("/users/"):]userId, subPath, _ := strings.Cut(remainder, "/")switch subPath {case "settings":fmt.Fprintf(w, "user %s", userId)// 其他子路径可以在这里添加default:http.NotFound(w, r)}})
【提升Go的HTTP路由器的提案】如果接受了这个提议,你可以更加简单地实现一样的功能:mux.HandleFunc("GET /users/{user}/settings", func(w http.ResponseWriter, r *http.Request) {fmt.Fprintf(w, "user %s", r.PathValue("user"))})
这样的写法明显更为简洁!这与其他流行路由器使用的语法非常相似:
// Github.com/go-chi/chirouter.Get("/users/{user}/settings", func(w http.ResponseWriter, r *http.Request) {fmt.Fprintf(w, "user %s", chi.URLParam(r, "slug"))})// github.com/gorilla/muxrouter.HandleFunc("/users/{user}/settings", func(w http.ResponseWriter, r *http.Request) {fmt.Fprintf(w, "user %s", mux.Vars(r)["user"])}).Methods("GET")// github.com/bmizerany/patrouter.Get("/users/:user/settings", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {fmt.Fprintf(w, "user %s", r.URL.Query().Get(":user"))}))// github.com/gin-gonic/ginrouter.GET("/users/:user/settings", func(c *gin.Context) {fmt.Fprintf(w, "user %s", c.Param("user"))})
提案中的一个有趣决定是,并没有为 ServeMux 添加新的方法;而是对现有的 Handle 和 HandleFunc 方法进行了扩展,以支持方法前缀和 {wildcard} 路径段 。我理解他们避免添加新方法的想法,但我对这个决定持保留态度 。遗憾的是,旧版的 ServeMux 接受如 Handle("GET /foo", h) 的模式 。这意味着为增强版 ServeMux 编写的代码将在旧版 Go 上能正常编译和运行,但路由不会匹配到任何内容,这容易导致错误 。我可能会添加新的方法,比如 HandleMatch / HandleMatchFunc 或 Route / RouteFunc 。
该提议也详细描述了处理两个重叠模式的优先级,其核心规则简单明了:“如果两个模式有重叠(有共同的请求),则更具体的模式优先匹配” 。
例如,如果你注册了模式 /users/(匹配 /users/*)以及模式 /users/{user},当一个 /users/ben 的请求进来时,它将匹配第二个,更具体的模式 。这与现有的 ServeMux 中,特定主机的模式优先于没有主机名的模式的行为一致 。
URL 末尾通配符匹配此提案为我们带来了一个新的"特殊通配符" {$},它专门用于匹配 URL 的末尾 。对于那些仅希望匹配主页路由的情况,这个新特性显得非常实用 。在此之前,要实现这一目标颇为麻烦,因为以 / 结尾的模式会匹配所有 / 之下的内容;这个规则对于只有 / 的模式同样适用 。
因此,以前若想匹配主页,你需要这样操作:
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {if r.URL.Path != "/" { // 确保路径就是 "/"http.NotFound(w, r)return}serveHomepage(w, r)})mux.HandleFunc("/users", serveUsers)
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 虚拟现实技术在工作场所的未来
- 警惕 C++ 中的隐式类型转换
- 不止 Win11,Win10 也获得了新的 Windows 备份应用
- 王小川谈ChatGPT:程序员是自己的“掘墓人”
- 定制自己的ChatGPT:免费用户也能使用“自定义”功能了!
- 眉曼颜:小挑眉是指在眉峰处微向上挑起的眉形,可增加眉毛立体感
- 10条你必须要知道的减肥热知识
- 打造你我的“诗与远方” 民宿管家从业者规模达百万级
- 八、九月,迎来许多贵人,诸事大吉,职场顺利,满是惊喜的3生肖
- 毁三观!曝音乐圈模范丁克夫妻形婚多年,各玩各的男方已有私生子