Caractères génériques dans le modèle pour http.HandleFunc

Lorsque vous enregistrez des gestionnaires dans Go (language), existe-t-il un moyen de spécifier des caractères génériques dans le modèle?

Par exemple:

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

Où le * pourrait être une chaîne d’URL valide. Ou est la seule solution pour faire correspondre /groups et calculer le rest dans le gestionnaire ( peopleInGroupHandler ) func?

Les modèles pour http.Handler et http.HandleFunc ne sont pas des expressions régulières ou des globes. Il n’y a aucun moyen de spécifier des caractères génériques. Ils sont documentés ici .

Cela dit, il n’est pas trop difficile de créer votre propre gestionnaire pouvant utiliser des expressions régulières ou tout autre type de motif souhaité. En voici un qui utilise des expressions régulières (compilées, mais non testées):

 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.MatchSsortingng(r.URL.Path) { route.handler.ServeHTTP(w, r) return } } // no pattern matched; send 404 response http.NotFound(w, r) } 

Depuis 2011, vous pouvez maintenant (2014+) trouver d’autres solutions.
Par exemple, le package mux du toolkit Gorilla Web fournit toutes sortes d’options de routage:

  • Correspondance de modèle sur les chemins de requête, avec des expressions régulières facultatives.
  • Correspondance sur l’hôte et le schéma d’URL, la méthode de requête, les valeurs d’en-tête et de requête.
  • Correspondance basée sur des fonctions personnalisées.
  • Utilisation de sous-routeurs pour un routage nested facile.

Il peut être facilement intégré à toute bibliothèque http de BYOR (Apportez votre propre routeur), comme negroni .

Voici un exemple tiré de l’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:[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)) } 

Parfois, mieux vaut ne pas simplement utiliser un autre paquet “magique”, mais comprendre ce qui se passe sous le capot

Dans ce cas, la “magie” est définie dans ” gorilla/mux/regexp.go ” et testée ici .
L’idée est d’extraire les variables nommées, d’assembler une expression régulière à mettre en correspondance, de créer un modèle “inverse” pour créer des URL et de comstackr les expressions rationnelles pour valider les valeurs de variable utilisées dans la création d’URL.

Je voulais juste append julienschmidt/httprouter , qui se comporte comme net/http mais avec un paramètre supplémentaire pour les valeurs d’url et le support des méthodes de requête:

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

Il semble aussi être un peu plus populaire que gorilla/mux (selon GitHub) et il prétend aussi avoir besoin de moins de mémoire.

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

Vous pouvez vérifier comment violetear gère les patterns dynamics + catchall (joker), ceci est juste pour compléter par exemple:

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

Dans ce cas, la requête peut avoir 2 UUIDS différents

Pour un caractère générique / dynamic, cela pourrait s’appliquer:

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

Une expression régulière peut être utilisée pour correspondre à l’adresse IP:

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

Ou simplement un catch all permettant uniquement les méthodes GET et HEAD :

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

Plus d’exemples peuvent être trouvés ici: https://violetear.org/post/how-it-works/

Beego, la réponse à toutes les questions du serveur web Golang. Wetalk est un site de blog construit sur Beego.