HttpRouter
Repositorio: julienschmidt/httprouter: A high performance HTTP request router that scales well (github.com)
El componente de enrutamiento que usa Gin es HttpRouter, este también es un componente de enrutamiento ligero y de alto rendimiento, todo el componente tiene solo tres archivos .go, el código es muy conciso, sus características principales son las siguientes.
Correspondencia uno a uno: Una solicitud solo puede coincidir con cero o una ruta, y es favorable para la optimización de SEO.
Corrección automática de ruta: Elige el estilo de URL que prefieras, incluso si hay una barra inclinada de más o de menos, se redirigirá automáticamente. Si hay errores de mayúsculas y minúsculas, también se ignorarán las mayúsculas y minúsculas al buscar y se redirigirá correctamente.
Análisis automático de parámetros de ruta: Solo dale un nombre al segmento de ruta, el enrutador te pasará los valores dinámicos. Debido al diseño del enrutador, el costo de análisis de parámetros de ruta es muy bajo.
Cero basura: Durante el proceso de enrutamiento y programación, no se generará ninguna memoria basura.
Soporte RefstfulAPI: El diseño del enrutador fomenta una API Restful razonable y en capas.
Manejo de errores: Se puede establecer un manejador de errores para manejar las excepciones en las solicitudes, el enrutador las capturará y registrará, luego redirigirá a la página de error.
Uso básico
Al igual que springboot, una función se vincula a una URL y corresponde a un procesador.
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))
}Luego usa el navegador o cualquier herramienta de prueba de interfaces para ingresar 127.0.0.1:8080, puedes ver el contenido correcto, podemos ver que HttpRouter solo hace el enrutamiento, en realidad todavía usa el componente predeterminado net/http, gin también es así, solo que la encapsulación es relativamente más profunda.
Parámetros con nombre
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))
}Esta vez se agregó un :name después de la ruta, name es un parámetro con nombre, se puede acceder al slice de parámetros a través de httprouter.Params, se puede obtener el parámetro por índice o ByName(name). De la misma manera, puedes usar http.handler y http.handlerFunc como httprouter.handler, la ruta en sí implementa su interfaz, por ejemplo el siguiente ejemplo.
func Hello(w http.ResponseWriter, r *http.Request) {
params := httprouter.ParamsFromContext(r.Context())
//params := r.Context().Value(httprouter.ParamsKey) también es posible
fmt.Fprintf(w, "hello, %s!\n", params.ByName("name"))
}Cuando la ruta vinculada al método es /user/:user, las siguientes situaciones de coincidencia de URL
/user/gordon coincide
/user/you coincide
/user/gordon/profile no coincide
/user/ no coincideNo puedes registrar /user/new y /user/:user en el mismo método de solicitud, cada método de solicitud debe ser independiente entre sí.
Capturar todos los parámetros
El segundo tipo es capturar todos los parámetros, como su nombre indica, coinciden con todo, por lo tanto, deben estar al final del Pattern.
Pattern: /src/*filepath
/src/ coincide
/src/somefile.go coincide
/src/subdir/somefile.go coincideEl principio de funcionamiento de HttpRouter es construir una gran cantidad de árboles de prefijos, los interesados pueden entender: httprouter package - github.com/julienschmidt/httprouter - Go Packages.
OPTIONS & CORS
Algunas personas pueden esperar modificar la respuesta automática para OPTIONS y establecer algunos encabezados de respuesta para adaptarse a las solicitudes de pre-vuelo de CORS, estas necesidades se pueden lograr usando el manejador Router.GlobalOPTIONS.
router.GlobalOPTIONS = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Header.Get("Access-Control-Request-Method") != "" {
// establecer encabezados de respuesta CORS
header := w.Header()
header.Set("Access-Control-Allow-Methods", r.Header.Get("Allow"))
header.Set("Access-Control-Allow-Origin", "*")
}
// adaptar código de estado 204
w.WriteHeader(http.StatusNoContent)
})Manejador NOT FOUND
TIP
Puede ser necesario desactivar Router.HandleMethodNotAllowed para evitar algunos problemas.
router.NotFound = http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
// tu lógica
})Verificación básica
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) {
// obtener credenciales de autenticación básicas
user, password, hasAuth := r.BasicAuth()
if hasAuth && user == requiredUser && password == requiredPassword {
// delegar la solicitud al procesador dado
h(w, r, ps)
} else {
// de lo contrario solicitar autenticación
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))
}