Wildcards in the template for http.HandleFunc

When registering handlers in Go (language), is there a way to specify wildcards in the template?

For example:

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

Where * can be any valid URL string. Or is this the only solution for matching /groups and calculating the rest from within the ( peopleInGroupHandler ) func handler?

+63
regex go
Jul 03 '11 at 18:00
source share
6 answers

Templates for http.Handler and http.HandleFunc are not regular expressions or globes. There is no way to specify wildcards. They are documented here .

However, it’s not too difficult to create your own handler that can use regular expressions or any other type of pattern that you want. Here's the 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) } 
+85
Jul 03 2018-11-11T00:
source

Since 2011, you can (2014+) find other solutions.
For example, the Gorilla Web multilingual package package offers all kinds of routing:

  • Match patterns on query paths with optional regular expressions.
  • Compliance with host and URL pattern, request method, header and request values.
  • Compliance based on custom features.
  • Using sub-routers for easy nested routing.

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

Here is an example from the article " Gorilla vs Pat vs Routes: Mux Showdown ":

 package main import ( "github.com/gorilla/mux" "log" "net/http" ) func main() { rtr := mux.NewRouter() rtr.HandleFunc("/user/{name:[az]+}/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 it’s better not just to use another β€œmagic” package, but understand what is happening under the hood

In this case, "magic" is defined in " gorilla/mux/regexp.go " and is tested here .
The idea is to retrieve named variables, compile a regular expression to match, create a "reverse" pattern to create URLs, and compile regular expressions to check the values ​​of the variables used in the construction of the URL.

+54
Aug 30 '14 at 9:00 a.m.
source

I just wanted to add julienschmidt/httprouter , which behaves like net/http , but with an extra 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!\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)) } 

It also seems a bit more popular than gorilla/mux (according to GitHub), and claims it needs less memory.

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

+6
Oct. 14 '15 at 8:55
source

You can check how violetear handles dynamic + catchall (wildcard) templates, this is just to 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 can apply:

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

A regular expression can be used to match IP:

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

Or just just catch everything that only the GET and HEAD methods allow:

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

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

+1
Sep 10 '17 at 11:47 on
source

Here is an example of how to use the sample code from @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) } 
+1
Aug 22 '19 at 18:18
source

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

-eleven
Dec 04 '13 at 17:06
source



All Articles