Go1.22 新特性:终于增强 http.ServerMux 路由能力,将有更强的表现力!

大家好,我是煎鱼。

Go1.22 有一个比较重要的新特性,那就是基于提案《net/http: enhanced ServeMux routing》,增强了 http.ServerMux 的路由匹配能力。非常值得大家学习和关注。

本次的新特性主要是新增了 HTTP 方法和路径变量。

快速学习

在 Go 中,可以认为几乎所有的路由相关的库都会基于 net/http 或是兼容其 interface。否则容易脱离一个标准路线。

本文的主角 ServeMux,函数签名如下:

go 复制代码
type ServeMux
func NewServeMux() *ServeMux
func (mux *ServeMux) Handle(pattern string, handler Handler)
func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request))
func (mux *ServeMux) Handler(r *Request) (h Handler, pattern string)
func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request)

最简单的 Demo 如下:

go 复制代码
type apiHandler struct{}

func (apiHandler) ServeHTTP(http.ResponseWriter, *http.Request) {}

func main() {
	mux := http.NewServeMux()
	mux.Handle("/api/", apiHandler{})
	mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
		...
		fmt.Fprintf(w, "你好,煎鱼!)
	})
}

用法非常的简单和标准,就是路径和实现方法。

新提案

缘由

这是一个很少见的提案,居然没有显著的说明没有这个的缺陷或问题。说明大家在潜意识里已经是比较认可的,不需要额外解释。

原因应该是:net/http.ServeMux 所提供的路由功能过于的基础了。

因此路由使用上,很多人都不优先推荐使用 net/http,而是更推荐 gorilla/mux 等知名开源库作为基础库,提高实现的效率和产能。

本次新提案将会增加:模式匹配、路径变量的支持。

Go1.22 路由增强

匹配方法

模式匹配将支持以 HTTP 方法开头,后跟空格,如 GET /eddycjy 或 GET eddycjy.com/ 中。 带有方法的模式仅用于匹配具有该方法的请求。

对照到代码中,也就是 Go1.22 起,http.ServeMux 可以这么写:

go 复制代码
mux.HandleFunc("POST /eddycjy/create", func(w http.ResponseWriter, r *http.Request) {
    fmt.Fprint(w, "脑子进煎鱼了!")
})

mux.HandleFunc("GET /eddycjy/update", func(w http.ResponseWriter, r *http.Request) {
    fmt.Fprint(w, "煎鱼进脑子了...")
})
...

通配符

模式匹配将支持 {name}{name...},例如:/b/{bucket}/o/{objectname...}

该名称必须是有效的 Go 标识符和符合完整路径元素的标准。它们前面必须有斜杠,后面必须有斜杠或字符串末尾。例如:/b_{bucket} 不是有效的通配模式。

Go1.22 起,http.ServeMux 可以这么写:

go 复制代码
mux.HandleFunc("/eddycjy/{id}", func(w http.ResponseWriter, r *http.Request) {
    id := r.PathValue("id")
    fmt.Fprintf(w, "id 值为 %s", id)
})

mux.HandleFunc("/eddycjy/{path...}", func(w http.ResponseWriter, r *http.Request) {
    path := r.PathValue("path")
    fmt.Fprintf(w, "path 值为 %s", path)
})
...

优先级

单一的优先规则:

  1. 如果两个模式重叠(有一些共同的请求),那么更具体的模式优先。
  2. 如果 P1 符合 P2 请求的一个(严格)子集,也就是说:如果 P2 符合 P1 的所有请求及更多请求,那么 P1 就比 P2 更具体。
  3. 如果两者都不更具体,那么模式就会发生冲突。
  4. 这条规则有一个例外:如果两个模式发生冲突,而其中一个有 HOST ,另一个没有,那么有 HOST 的模式优先。

以下是图示参考:

具体的例子:

  • example.com// 更具体,因为第一个仅匹配主机 example.com 的请求,而第二个匹配任何请求。
  • GET // 更具体,因为第一个仅匹配 GET 和 HEAD 请求,而第二个匹配任何请求。
  • /b/{bucket}/o/default/b/{bucket}/o/{noun} 更具体,因为第一个仅匹配第四个元素是文字 "default" 的路径,而在第二个中,第四个元素可以是任何内容。

总结

今天我们分享了 Go1.22 对于 net/http 标注库中的 ServerMux 路由相关功能的增强。

Go 还是有在吸收第三方开源库的一些不错的地方的,就是慢了一些。这都 10 多年了...

文章持续更新,可以微信搜【脑子进煎鱼了】阅读,本文 GitHub github.com/eddycjy/blo... 已收录,学习 Go 语言可以看 Go 学习地图和路线,欢迎 Star 催更。

推荐阅读

相关推荐
研究司马懿21 小时前
【云原生】Gateway API高级功能
云原生·go·gateway·k8s·gateway api
梦想很大很大1 天前
使用 Go + Gin + Fx 构建工程化后端服务模板(gin-app 实践)
前端·后端·go
lekami_兰2 天前
MySQL 长事务:藏在业务里的性能 “隐形杀手”
数据库·mysql·go·长事务
却尘2 天前
一篇小白也能看懂的 Go 字符串拼接 & Builder & cap 全家桶
后端·go
ん贤2 天前
一次批量删除引发的死锁,最终我选择不加锁
数据库·安全·go·死锁
mtngt112 天前
AI DDD重构实践
go
Grassto4 天前
12 go.sum 是如何保证依赖安全的?校验机制源码解析
安全·golang·go·哈希算法·go module
Grassto6 天前
11 Go Module 缓存机制详解
开发语言·缓存·golang·go·go module
程序设计实验室7 天前
2025年的最后一天,分享我使用go语言开发的电子书转换工具网站
go
我的golang之路果然有问题7 天前
使用 Hugo + GitHub Pages + PaperMod 主题 + Obsidian 搭建开发博客
golang·go·github·博客·个人开发·个人博客·hugo