Skip to content

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.

go
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

go
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.

go
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 match

Non 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.

go
Pattern: /src/*filepath

 /src/                     match
 /src/somefile.go          match
 /src/subdir/somefile.go   match

Il 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.

go
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.

go
router.NotFound = http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
  // tua logica
})

Verifica Base

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

Golang by www.golangdev.cn edit