HttpRouter
Repositório: julienschmidt/httprouter: A high performance HTTP request router that scales well (github.com)
O componente de roteamento do Gin usa HttpRouter, que também é um componente de roteamento leve e de alto desempenho. Todo o componente consiste em apenas três arquivos .go, o código é bastante conciso, e possui as seguintes características principais.
Correspondência Um-para-Um: Uma requisição só pode corresponder a zero ou uma rota, e é benéfico para otimização de SEO.
Correção Automática de Caminho: Escolha livremente o estilo de URL preferido, mesmo que haja uma barra a mais ou a menos, haverá redirecionamento automático. Se houver erros de maiúsculas/minúsculas, a busca ignorará maiúsculas/minúsculas para redirecionamento correto.
Análise Automática de Parâmetros de Rota: Basta dar um nome ao segmento de caminho, e o roteador passará os valores dinâmicos para você. Devido ao design do roteador, a sobrecarga de análise de parâmetros de caminho é muito baixa.
Zero Lixo: Durante o processo de alocação e agendamento de rotas, nenhum lixo de memória é gerado.
Suporte a RefstfulAPI: O design do roteador incentiva APIs Restful razoavelmente hierárquicas.
Tratamento de Erros: É possível definir um manipulador de erros para lidar com anomalias nas requisições, o roteador as capturará e registrará, depois redirecionará para a página de erro.
Uso Básico
Assim como no springboot, uma função é vinculada a uma URL e corresponde a um processador.
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))
}Em seguida, usando um navegador ou qualquer ferramenta de teste de API, acesse 127.0.0.1:8080 para ver o conteúdo correto. Podemos ver que HttpRouter apenas faz o roteamento, e na verdade ainda usa o componente padrão net/http, o gin também é assim, apenas o encapsulamento é relativamente mais profundo.
Parâmetros Nomeados
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))
}Desta vez, um :name foi adicionado após a rota, onde name é um parâmetro nomeado, e é possível acessar o slice de parâmetros através de httprouter.Params, podendo obter o parâmetro por índice ou ByName(name). Da mesma forma, é possível usar http.Handler e http.HandlerFunc como httprouter.Handle, a rota em si implementa sua interface, como no exemplo abaixo.
func Hello(w http.ResponseWriter, r *http.Request) {
params := httprouter.ParamsFromContext(r.Context())
//params := r.Context().Value(httprouter.ParamsKey) também funciona
fmt.Fprintf(w, "hello, %s!\n", params.ByName("name"))
}Quando a rota vinculada ao método é /user/:user, as seguintes situações de correspondência de URL ocorrem:
/user/gordon corresponde
/user/you corresponde
/user/gordon/profile não corresponde
/user/ não correspondeVocê não pode registrar /user/new e /user/:user no mesmo método de requisição, cada método de requisição deve ser independente.
Capturar Todos os Parâmetros
O segundo tipo é capturar todos os parâmetros, como o nome sugere, eles correspondem a tudo, portanto devem estar no final do Pattern.
Pattern: /src/*filepath
/src/ corresponde
/src/somefile.go corresponde
/src/subdir/somefile.go correspondeO princípio de funcionamento do HttpRouter é construir uma grande quantidade de árvores de prefixo, interessados podem consultar: httprouter package - github.com/julienschmidt/httprouter - Go Packages.
OPTIONS & CORS
Algumas pessoas podem desejar modificar a resposta automática para OPTIONS e definir alguns cabeçalhos de resposta para adaptar a requisição de pré-voo CORS, essas necessidades podem ser atendidas usando o manipulador Router.GlobalOPTIONS.
router.GlobalOPTIONS = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Header.Get("Access-Control-Request-Method") != "" {
// Define cabeçalhos de resposta CORS
header := w.Header()
header.Set("Access-Control-Allow-Methods", r.Header.Get("Allow"))
header.Set("Access-Control-Allow-Origin", "*")
}
// Adapta código de status 204
w.WriteHeader(http.StatusNoContent)
})Manipulador NOT FOUND
TIP
Pode ser necessário desativar Router.HandleMethodNotAllowed para evitar alguns problemas.
router.NotFound = http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
// sua lógica
})Validação 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) {
// Obtém credenciais de autenticação básica
user, password, hasAuth := r.BasicAuth()
if hasAuth && user == requiredUser && password == requiredPassword {
// Delega a requisição ao manipulador fornecido
h(w, r, ps)
} else {
// Caso contrário, solicita autenticação
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))
}