HttpRouter
Repository: julienschmidt/httprouter: A high performance HTTP request router that scales well (github.com)
Il componente di routing utilizzato da Gin è HttpRouter, che è anche un componente di routing leggero e ad alte prestazioni, l'intero componente ha solo tre file .go, il codice è molto conciso, le sue caratteristiche principali sono le seguenti.
Corrispondenza uno-a-uno: Una richiesta può corrispondere solo a zero o un route, ed è favorevole all'ottimizzazione SEO.
Correzione automatica percorso: Scegli lo stile URL che preferisci, anche se manca o c'è un trattino in più, verrà reindirizzato automaticamente. Se ci sono errori di maiuscole/minuscole, verranno ignorati durante la ricerca per un reindirizzamento corretto.
Analisi automatica parametri route: Basta dare un nome al segmento di percorso e il router ti passerà i valori dinamici. Grazie al design del router, l'occupazione dell'analisi dei parametri di percorso è molto bassa.
Zero garbage: Durante il processo di allocazione e schedulazione delle route, non viene generato alcun garbage di memoria.
Supporto RefstfulAPI: Il design del router incoraggia API Restful ragionevolmente stratificate.
Gestione errori: È possibile impostare un gestore errori per gestire le eccezioni nelle richieste, il router le catturerà e registrerà, quindi reindirizzerà alla pagina di errore.
Utilizzo Base
Come springboot, una funzione è legata a un URL e corrisponde a un handler.
package main
import (
"fmt"
"github.com/julienschmidt/httprouter"
"log"
"net/http"
)
func Hello(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
fmt.Fprintf(w, "<h1>Hello World!")
}
func main() {
router := httprouter.New()
router.GET("/hello", Hello)
log.Fatal(http.ListenAndServe(":8080", router))
}Poi usa il browser o qualsiasi strumento di test delle interfacce per inserire 127.0.0.1:8080, puoi vedere il contenuto corretto, possiamo vedere che HttpRouter fa solo routing, in realtà usa ancora il componente predefinito net/http, anche gin è così, solo che l'incapsulamento è relativamente più profondo.
Parametri Denominati
package main
import (
"fmt"
"github.com/julienschmidt/httprouter"
"log"
"net/http"
)
func Hello(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
fmt.Fprintf(w, "<h1>Hello World!")
}
func main() {
router := httprouter.New()
router.GET("/hello:name", Hello)
log.Fatal(http.ListenAndServe(":8080", router))
}Questa volta c'è un :name dopo la route, name è un parametro denominato, è possibile accedere alla slice dei parametri tramite httprouter.Params, è possibile ottenere il parametro tramite indice o ByName(name). Allo stesso modo, puoi usare http.handler e http.handlerFunc come httprouter.handler, la route stessa implementa la sua interfaccia, ad esempio l'esempio seguente.
func Hello(w http.ResponseWriter, r *http.Request) {
params := httprouter.ParamsFromContext(r.Context())
//params := r.Context().Value(httprouter.ParamsKey) anche possibile
fmt.Fprintf(w, "hello, %s!\n", params.ByName("name"))
}Quando la route legata al metodo è /user/:user, le seguenti situazioni di corrispondenza URL
/user/gordon match
/user/you match
/user/gordon/profile no match
/user/ no matchNon puoi registrare /user/new e /user/:user sullo stesso metodo di richiesta, ogni metodo di richiesta dovrebbe essere indipendente.
Cattura Tutti i Parametri
Il secondo tipo è cattura tutti i parametri, come suggerisce il nome, corrispondono a tutto, quindi devono essere alla fine del Pattern.
Pattern: /src/*filepath
/src/ match
/src/somefile.go match
/src/subdir/somefile.go matchIl principio di funzionamento di HttpRouter è costruire un gran numero di alberi di prefisso, chi è interessato può comprendere: httprouter package - github.com/julienschmidt/httprouter - Go Packages.
OPTIONS & CORS
Alcune persone potrebbero voler modificare la risposta automatica per OPTIONS e impostare alcuni header di risposta per adattarsi alle richieste di preflight CORS, queste esigenze possono essere implementate usando l'handler Router.GlobalOPTIONS.
router.GlobalOPTIONS = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Header.Get("Access-Control-Request-Method") != "" {
// Imposta header di risposta CORS
header := w.Header()
header.Set("Access-Control-Allow-Methods", r.Header.Get("Allow"))
header.Set("Access-Control-Allow-Origin", "*")
}
// Adatta codice di stato 204
w.WriteHeader(http.StatusNoContent)
})Handler NOT FOUND
TIP
Potrebbe essere necessario disattivare Router.HandleMethodNotAllowed, per evitare alcuni problemi.
router.NotFound = http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
// tua logica
})Verifica Base
package main
import (
"fmt"
"log"
"net/http"
"github.com/julienschmidt/httprouter"
)
func BasicAuth(h httprouter.Handle, requiredUser, requiredPassword string) httprouter.Handle {
return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
// Ottieni credenziali di autenticazione base
user, password, hasAuth := r.BasicAuth()
if hasAuth && user == requiredUser && password == requiredPassword {
// Delega la richiesta all'handler fornito
h(w, r, ps)
} else {
// Altrimenti richiedi autenticazione
w.Header().Set("WWW-Authenticate", "Basic realm=Restricted")
http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
}
}
}
func Index(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
fmt.Fprint(w, "Not protected!\n")
}
func Protected(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
fmt.Fprint(w, "Protected!\n")
}
func main() {
user := "gordon"
pass := "secret!"
router := httprouter.New()
router.GET("/", Index)
router.GET("/protected/", BasicAuth(Protected, user, pass))
log.Fatal(http.ListenAndServe(":8080", router))
}