IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

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

    煎鱼发表于 2024-01-24 12:31:51
    love 0

    大家好,我是煎鱼。

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

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

    快速学习

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

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

    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 如下:

    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 可以这么写:

    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 可以这么写:

    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/blog 已收录,学习 Go 语言可以看 Go 学习地图和路线,欢迎 Star 催更。

    推荐阅读

    • Go1.22 新特性:for 循环不再共享循环变量,且支持整数范围
    • Go1.22 新特性:Slices 变更 Concat、Delete、Insert 等函数,对开发挺有帮助!
    • Go1.22 新特性:新的 math/rand/v2 库,更快更标准!


沪ICP备19023445号-2号
友情链接