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

    Go http.ServeMux中的模式匹配

    smallnest发表于 2023-12-25 15:22:52
    love 0

    Go 1.22中一个很大的变化是http.ServeMux中的模式匹配,先前这个功能是很多第三方的web框架或者router库实现的。

    我们很有必要好好研究它,将来在实现HTTP API的时候可能优先使用它。

    http.ServeMux是一个HTTP请求多路复用器,它将每个传入请求的URL与已注册的模式列表进行匹配,并调用与最接近URL匹配的模式对应的处理程序。

    比如:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    mux.HandleFunc("POST /items/create", func(w http.ResponseWriter, r *http.Request) {
    fmt.Fprint(w, "POST item created")
    })
    mux.HandleFunc("/items/create", func(w http.ResponseWriter, r *http.Request) {
    fmt.Fprint(w, "item created")
    })
    mux.HandleFunc("/items/{id}", func(w http.ResponseWriter, r *http.Request) {
    id := r.PathValue("id")
    fmt.Fprintf(w, "Item ID = %s", id)
    })
    mux.HandleFunc("/files/{path...}", func(w http.ResponseWriter, r *http.Request) {
    path := r.PathValue("path")
    fmt.Fprintf(w, "File path = %s", path)
    })

    和原来的HandleFunc相比,第一个参数貌似有了不一样的变化,除了正常的path之外,还有HTTP POST Method,还有{id}和{path...}这样的变量,这就是Go 1.22中新增加的模式匹配。

    通过PathValue可以获取路径中的通配符匹配的值。

    模式匹配

    模式匹配用在注册handler的时候,如下:

    1
    2
    func Handle(pattern string, handler Handler)
    func HandleFunc(pattern string, handler func(ResponseWriter, *Request))

    其中pattern模式的格式是这样子的:[METHOD ][HOST]/[PATH], 中括号代表这一项可以省略。
    因此POST /items/create、POST rpcx.io/items/create、GET /items/123、/items/123都是合法的模式。

    如果不设置HTTP Method如POST,那么默认是匹配所有的HTTP Method。注意HTTP Method 之后有一个空格。
    模式匹配GET会匹配GET和HEAD,除此之外,其他的HTTP Method都是精确匹配。

    如果未设置HOST,那么默认是匹配所有的HOST。否则,HOST必须完全匹配。

    通配符

    请求的路径中可以包含通配符,如"/b/{bucket}/o/{objectname...}"。配符名称必须是有效的Go标识符。通配符必须是完整的路径段,例如/b_{bucket}就不是一个合法的通配符。

    • /items/{id}: 正常情况下一个通配符只匹配一个路径段,比如匹配/items/123,但是不匹配/items/123/456。
    • /items/{apth...}: 但是如果通配符后面跟着...,那么它就会匹配多个路径段,比如/items/123、/items/123/456都会匹配这个模式。
    • /items/{$}: 以/结尾的模式会匹配所有以它为前缀的路径,比如/items/、/items/123、/items/123/456都会匹配这个模式。如果以/{$}为后缀,那么表示严格匹配路径,不会匹配带后缀的路径,比如这个例子只会匹配/items/,不会匹配/items/123、/items/123/456。

    在匹配过程中,模式路径和传入请求路径都会逐段解码。因此,例如,路径 /a%2Fb/100%25 被视为具有两个段,a/b 和 100%。模式 /a%2fb/ 与之匹配,但模式 /a/b/ 则不匹配。

    优先级

    如果两个模式都可以匹配同一个路径咋办呢?比如/items/{id}和/items/{path...}都可以匹配/items/123,那么谁优先呢?

    • 最具体的模式具有优先权。比如/items/{id}比/items/更具体。
    • 如果两者都不更具体,则模式冲突。
      • 在冲突的情况下,具有主机的模式具有优先权 rpcx.io/items/{id}比/items/{id}优先权更高。
      • 如果两者都没有HOST,则模式冲突,panic。 items/{id}和/items/{index}都没有HOST,所以会panic。

    后缀/的转发

    /images/ 会导致ServeMux把/images重定向到/images/除非你注册了/images的handler。

    请求清理

    ServeMux 还负责清理URL请求路径和Host标头,去除端口号,并将包含 . 或 .. 段或重复斜杠的任何请求重定向到等效、更清晰的URL。



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