ChatGPT解决这个技术问题 Extra ChatGPT

http.HandleFunc 模式中的通配符

在 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)

E
Evan Shaw

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}", handler)
Gorillatoolkit 在实现 PAT 和 MUX 以处理路由方面做得很好。唯一的问题是它很慢,我还没有查看代码。至少在他们的 API 中,可以命名参数……这是这类功能的重点。上面的代码没有提供任何复杂的东西,如果没有命名元素,它可能不会有用。
如果您只是在寻找类似“其他”* 的包罗万象,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 的原始示例中。你能举一个完整的例子吗?谢谢。
V
VonC

自 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 构建中使用的变量值。


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

我只是想添加 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


c
caike

这是如何使用来自@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
n
nbari

您可以检查 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/