【问题标题】:Wildcards in the pattern for http.HandleFunchttp.HandleFunc 模式中的通配符
【发布时间】:2011-09-27 17:14:14
【问题描述】:

在 Go(语言)中注册处理程序时,有没有办法在模式中指定通配符?

例如:

http.HandleFunc("/groups/*/people", peopleInGroupHandler)

* 可以是任何有效的 URL 字符串。或者是匹配 /groups 并从处理程序 (peopleInGroupHandler) func 中找出其余部分的唯一解决方案?

【问题讨论】:

  • 我可以看看你的输入字符串的例子,以及你目前得到的匹配吗?
  • 请参阅 goweb.googlecode.com,它为 Go 中的 Ruby on Rails 样式路由提供支持 - 即 goweb.MapFunc("/people/{person_id}/groups/{group_id}", handler)

标签: regex go


【解决方案1】:

这是一个如何使用来自@evanshaw 的代码示例的示例

func handleDigits(res http.ResponseWriter, req *http.Request) {
    res.Write([]byte("Digits in the URL\n"))
}

func handleStrings(res http.ResponseWriter, req *http.Request) {
    res.Write([]byte("Strings in the URL\n"))
}

func main() {
    handler := &RegexpHandler{}

    reg1, _ := regexp.Compile("/foo-\\d+")
    handler.HandleFunc(reg1, handleDigits)

    reg2, _ := regexp.Compile("/foo-\\w+")
    handler.HandleFunc(reg2, handleStrings)

    http.ListenAndServe(":3000", handler)
}

【讨论】:

  • 不能使用 reg2 (type *regexp.Regexp) 作为类型字符串 i│ n 参数到 http.HandleFunc
  • @CSQGB 如果您正确阅读了答案,它会说“这是如何使用@evanshaw 的代码示例的示例”,它不仅仅是代码。这使用了上面的示例。它甚至使用称为RegexpHandler 的不同处理程序,而不是http.HandleFunc
【解决方案2】:

我只是想添加julienschmidt/httprouter,它的行为类似于net/http,但带有一个额外的url-values参数和对请求方法的支持:

https://github.com/julienschmidt/httprouter

package main

import (
    "fmt"
    "github.com/julienschmidt/httprouter"
    "net/http"
    "log"
)

func Index(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
    fmt.Fprint(w, "Welcome!\n")
}

func Hello(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
    fmt.Fprintf(w, "hello, %s!\n", ps.ByName("name"))
}

func main() {
    router := httprouter.New()
    router.GET("/", Index)
    router.GET("/hello/:name", Hello)

    log.Fatal(http.ListenAndServe(":8080", router))
}

它似乎也比 gorilla/mux 更受欢迎(根据 GitHub),它还声称需要更少的内存。

https://github.com/julienschmidt/go-http-routing-benchmark

【讨论】:

    【解决方案3】:

    您可以检查violetear 如何处理动态 + 通用(通配符)模式,这只是为了补充例如:

    uuid := `[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}`
    router.AddRegex(":uuid")
    router.HandleFunc("/test/:uuid/:uuid", handleUUID, "GET,HEAD")
    

    在这种情况下,请求可能有 2 个不同的UUIDS

    对于动态/通配符,这可能适用:

    http://api.violetear.org/command/ping/127.0.0.1
                            \______/\___/\________/
                                |     |      |
                                 static      |
                                          dynamic
    

    可以使用正则表达式来匹配 IP:

    router.AddRegex(":ip", `^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$`)
    router.HandleFunc("/command/ping/:ip", ipHandler, "GET")
    

    或者只是一个只允许 GETHEAD 方法的捕获:

    router.HandleFunc("/command/ping/*", anyHandler, "GET, HEAD")
    

    更多示例可以在这里找到:https://violetear.org/post/how-it-works/

    【讨论】:

      【解决方案4】:

      自 2011 年以来,您现在(2014 年以上)可以找到其他解决方案。
      例如,mux package of the Gorilla Web toolkit 提供了各种路由选项:

      • 请求路径上的模式匹配,带有可选的正则表达式。
      • 匹配 URL 主机和方案、请求方法、标头和查询值。
      • 基于自定义函数的匹配。
      • 使用子路由器轻松嵌套路由。

      它可以轻松集成到任何 BYOR(自带路由器)http 库 like negroni

      以下是文章“Gorilla vs Pat vs Routes: A Mux Showdown”中的示例:

      package main
      
      import (
        "github.com/gorilla/mux"
        "log"
        "net/http"
      )
      
      func main() {
        rtr := mux.NewRouter()
        rtr.HandleFunc("/user/{name:[a-z]+}/profile", profile).Methods("GET")
      
        http.Handle("/", rtr)
      
        log.Println("Listening...")
        http.ListenAndServe(":3000", nil)
      }
      
      func profile(w http.ResponseWriter, r *http.Request) {
        params := mux.Vars(r)
        name := params["name"]
        w.Write([]byte("Hello " + name))
      }
      

      有时最好不要只使用另一个“神奇”包,而是了解引擎盖下发生了什么

      在这种情况下,“魔法”在“gorilla/mux/regexp.go”和tested here中定义。
      这个想法是提取命名变量,组装一个要匹配的正则表达式,创建一个“反向”模板来构建 URL,并编译正则表达式来验证 URL 构建中使用的变量值。

      【讨论】:

      • 因为它更新了很多。给它时间:)
      • 因为有时最好不要只使用另一个“神奇”包,而是了解引擎盖下发生了什么:)
      【解决方案5】:

      Beego,所有 Golang Web 服务器问题的答案。 Wetalk 是一个基于 Beego 构建的博客网站。

      【讨论】:

      • “虽然此链接可能会回答问题,但最好在此处包含答案的基本部分并提供链接以供参考。如果链接页面发生更改,仅链接的答案可能会失效。”
      【解决方案6】:

      http.Handler 和 http.HandleFunc 的模式不是正则表达式或 glob。没有办法指定通配符。他们被记录在here

      也就是说,创建自己的处理程序并不难,它可以使用正则表达式或您想要的任何其他类型的模式。这是一个使用正则表达式(已编译,但未经测试):

      type route struct {
          pattern *regexp.Regexp
          handler http.Handler
      }
      
      type RegexpHandler struct {
          routes []*route
      }
      
      func (h *RegexpHandler) Handler(pattern *regexp.Regexp, handler http.Handler) {
          h.routes = append(h.routes, &route{pattern, handler})
      }
      
      func (h *RegexpHandler) HandleFunc(pattern *regexp.Regexp, handler func(http.ResponseWriter, *http.Request)) {
          h.routes = append(h.routes, &route{pattern, http.HandlerFunc(handler)})
      }
      
      func (h *RegexpHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
          for _, route := range h.routes {
              if route.pattern.MatchString(r.URL.Path) {
                  route.handler.ServeHTTP(w, r)
                  return
              }
          }
          // no pattern matched; send 404 response
          http.NotFound(w, r)
      }
      

      【讨论】:

      • 因为我想要在 Go 中使用 ruby​​ on rails 风格的路线,我已经启动了允许这种风格的路线映射的 goweb 项目(参见 goweb.googlecode.com):goweb.MapFunc("/people/{person_id} ", 处理程序)
      • Gorillatoolkit 在实现 PAT 和 MUX 处理路由方面做得很好。唯一的问题是它很慢,我还没有查看代码。至少在他们的 API 中,可以命名参数……这是这种功能的重点。上面的代码没有提供任何复杂的东西,如果没有命名元素,可能就没有用处。
      • 如果您只是在寻找“否则”*-like 包罗万象,the docs 需要注意的是the pattern "/" matches all paths not matched by other registered patterns
      • 也许(h *RegexpHandler) Handler 应该是(h *RegexpHandler) Handle?见这里:golang.org/pkg/net/http/#ServeMux.Handle :)
      • 如何将代码集成到net/http的原始示例中。你能举一个完整的例子吗?谢谢。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-03-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多