http.HandleFunc模式中的通配符

时间:2011-07-03 18:00:45

标签: regex go

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

例如:

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

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

6 个答案:

答案 0 :(得分:82)

http.Handler和http.HandleFunc的模式不是正则表达式或整数。没有办法指定通配符。他们记录在案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)
}

答案 1 :(得分:54)

自2011年起,您现在可以(2014年以上)找到其他解决方案 例如,mux package of the Gorilla Web toolkit提供了所有类型的路由选项:

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

它可以轻松集成到任何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构建中使用的变量值。

答案 2 :(得分:6)

我只想添加from pbkdf2 import PBKDF2 ,其行为与pip show -f <package>类似,但附加了url值参数和对请求方法的支持:

https://github.com/julienschmidt/httprouter

julienschmidt/httprouter

它似乎比net/http稍微受欢迎(根据GitHub),它也声称需要更少的内存。

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

答案 3 :(得分:1)

您可以查看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 :(得分: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)
}

答案 5 :(得分:-11)

Beego,所有Golang网络服务器问题的答案。 Wetalk是一个建立在Beego上的博客网站。