Lors de l'enregistrement de gestionnaires dans Go (langue), 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 *
peut être n'importe quelle chaîne d'URL valide. Ou est la seule solution pour correspondre à /groups
et comprendre le reste depuis 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 qui peut utiliser des expressions régulières ou tout autre type de modèle que vous souhaitez. En voici une 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.MatchString(r.URL.Path) {
route.handler.ServeHTTP(w, r)
return
}
}
// no pattern matched; send 404 response
http.NotFound(w, r)
}
Depuis 2011, vous pouvez désormais (2014+) trouver d'autres solutions.
Par exemple, le package mux du Gorilla Web toolkit fournit toutes sortes d'options de routage:
Il peut être facilement intégré à n'importe quelle bibliothèque http BYOR (Bring your own Router), comme negroni .
Voici un exemple 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:[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))
}
Parfois, il vaut mieux ne pas simplement utiliser un autre package "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é ici .
.
Je voulais juste ajouter julienschmidt/httprouter
, qui se comporte comme net/http
mais avec un paramètre supplémentaire pour les valeurs d'url et la prise en charge des méthodes de demande:
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 également être légèrement plus populaire que gorilla/mux
(selon GitHub) et il prétend également avoir besoin de moins de mémoire.
Vous pouvez vérifier comment violetear gère les modèles dynamiques + catchall (wildcard), c'est juste pour le complément 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 demande peut avoir 2 UUIDS
différents
Pour un dynamique/caractère générique, 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'IP:
router.AddRegex(":ip", `^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$`)
router.HandleFunc("/command/ping/:ip", ipHandler, "GET")
Ou tout 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/
Voici un exemple d'utilisation de l'exemple de code de @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)
}