duanlie1298
2011-07-03 18:00
浏览 287
已采纳

http.HandleFunc模式中的通配符

When registering handlers in Go (language) is there any way to specify wildcards in the pattern?

For example:

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

Where the * could be any valid URL string. Or is the only solution to match /groups and figure the rest out from within the handler (peopleInGroupHandler) func?

图片转代码服务由CSDN问答提供 功能建议

在Go(语言)中注册处理程序时,是否可以在模式中指定通配符? \ n

例如:

  http.HandleFunc(“ / groups / * / people”,peopleInGroupHandler)
   
  
 

其中 * 可以是任何有效的URL字符串。 还是唯一匹配 / groups 并从处理程序( peopleInGroupHandler )函数中找出其余内容的解决方案?

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 邀请回答

6条回答 默认 最新

  • douchun6108 2011-07-03 20:34
    已采纳

    The patterns for http.Handler and http.HandleFunc aren't regular expressions or globs. There isn't a way to specify wildcards. They're documented here.

    That said, it's not too hard to create your own handler that can use regular expressions or any other kind of pattern you want. Here's one that uses regular expressions (compiled, but not tested):

    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)
    }
    
    点赞 打赏 评论
  • dongzhang1839 2013-12-04 17:06

    Beego, the answer to all the Golang web server questions. Wetalk is a blog site built on Beego.

    点赞 打赏 评论
  • douhui7136 2014-08-30 09:00

    Since 2011, you can now (2014+) find other solutions.
    For instance, the mux package of the Gorilla Web toolkit provides all kind of routing options:

    • Pattern matching on request paths, with optional regular expressions.
    • Matching on URL host and scheme, request method, header and query values.
    • Matching based on custom functions.
    • Use of sub-routers for easy nested routing.

    It can be easily integrated to any BYOR (Bring your own Router) http library, like negroni.

    Here is an example from the article "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))
    }
    

    Sometimes better not to just use yet another "magic" package, but understand what's going on under the hood

    In this instance, the "magic" is defined in "gorilla/mux/regexp.go", and tested here.
    The idea is to extract named variables, assemble a regexp to be matched, create a "reverse" template to build URLs and compile regexps to validate variable values used in URL building.

    点赞 打赏 评论
  • duanliaoyin3171 2015-10-14 08:55

    I just wanted to add julienschmidt/httprouter, which just behaves like net/http but with an additional parameter for url-values and support for request methods:

    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!
    ")
    }
    
    func Hello(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
        fmt.Fprintf(w, "hello, %s!
    ", ps.ByName("name"))
    }
    
    func main() {
        router := httprouter.New()
        router.GET("/", Index)
        router.GET("/hello/:name", Hello)
    
        log.Fatal(http.ListenAndServe(":8080", router))
    }
    

    It also seems to be slightly more popular than gorilla/mux (according to GitHub) and it also claims to need less memory.

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

    点赞 打赏 评论
  • dongzhi7641 2017-09-10 11:47

    You could check how violetear handles dynamic + catchall (wildcard) patterns, this is just for complement for example:

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

    In this case, the request may have 2 different UUIDS

    For a dynamic/wildcard this could apply:

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

    A regex may be used to match the IP:

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

    Or simply just a catch all allowing GET and HEAD methods only:

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

    More examples can be found here: https://violetear.org/post/how-it-works/

    点赞 打赏 评论
  • doupi6737 2019-08-22 18:18

    Here's an example of how to use the code example from @evanshaw

    func handleDigits(res http.ResponseWriter, req *http.Request) {
        res.Write([]byte("Digits in the URL
    "))
    }
    
    func handleStrings(res http.ResponseWriter, req *http.Request) {
        res.Write([]byte("Strings in the URL
    "))
    }
    
    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)
    }
    
    点赞 打赏 评论

相关推荐 更多相似问题