En Oppsummering Av Forespørselshåndtering I Go
Behandling AV HTTP-forespørsler med Go handler først og fremst om to ting: ServeMuxes og Handlers.
En ServeMux er i hovedsak EN HTTP request router (eller multiplexor). Den sammenligner innkommende forespørsler mot en liste over forhåndsdefinerte url-baner, og kaller den tilknyttede behandleren for banen når en kamp er funnet.
Handlers er ansvarlig for å skrive svar overskrifter og organer. Nesten ethvert objekt kan være en handler, så lenge det tilfredsstiller http.Handler
– grensesnittet. I lay-termer betyr det ganske enkelt at Det må ha en ServeHTTP
metode med følgende signatur:
ServeHTTP(http.ResponseWriter, *http.Request)
GOS HTTP-pakke leveres med noen få funksjoner for å generere vanlige behandlere, for eksempelFileServer
NotFoundHandler
ogRedirectHandler
. La oss begynne med et enkelt, men konstruert eksempel:
La oss gå gjennom dette raskt:
- I
main
– funksjonen bruker vihttp.NewServeMux
– funksjonen slik oppretter du en tom servemux. - vi bruker da
http.RedirectHandler
funksjonen for å opprette en ny handler. Denne behandleren 307 omdirigerer alle forespørsler den mottar tilhttp://example.org
. - neste bruker vi
mux.Handle
funksjonen for å registrere dette med vår Nye ServeMux, så det fungerer som håndterer for alle innkommende forespørsler med URL-banen/foo
. - Endelig oppretter vi en ny server og begynne å lytte for innkommende forespørsler med
http.ListenAndServe
funksjon, passerer i Vår ServeMux for det å matche forespørsler mot.
gå videre og kjør programmet:
og besøkhttp://localhost:3000/foo
i nettleseren din. Du bør finne at forespørselen blir omdirigert.
eagle-eyed av dere har kanskje lagt merke til noe interessant: signaturen for ListenAndServe-funksjonen er ListenAndServe(addr string, handler Handler)
, men Vi passerte En ServeMux som den andre parameteren.
Vi kunne gjøre dette fordi ServeMux-typen også har enServeHTTP
metode, noe som betyr at Den også tilfredsstiller Håndterings grensesnittet.
for meg forenkler det ting å tenke På En ServeMux som bare å være en spesiell type handler, som i stedet for å gi et svar selv sender forespørselen videre til en annen handler. Dette er ikke så mye av et sprang som det først høres ut-kjedehåndterere sammen er ganske vanlig I Go.
Tilpassede Behandlere
la oss lage en tilpasset behandlere som svarer med gjeldende lokal tid i et gitt format:
den nøyaktige koden her er ikke så viktig.
Alt som virkelig betyr noe er at vi har et objekt (i dette tilfellet er det en timeHandler
struct, men det kan også være en streng eller funksjon eller noe annet), og vi har implementert en metode med signaturen ServeHTTP(http.ResponseWriter, *http.Request)
på den. Det er alt vi trenger for å lage en handler.
la oss legge inn dette i et konkret eksempel:
i main
– funksjonen initialiserte vi timeHandler
på nøyaktig samme måte som vi ville gjort med en hvilken som helst normal struktur ved å bruke &
symbol for å gi en peker. Og så, som forrige eksempel, bruker vi mux.Handle
– funksjonen for å registrere dette med Vår ServeMux.
Nå når vi kjører programmet, Vil ServeMux passere enhver forespørsel om /time
rett til vår timeHandler.ServeHTTP
metode.
Gå videre og gi det et forsøk: http://localhost:3000/time
.
Legg Også Merke til at vi lett kunne gjenbruke timeHandler
i flere ruter:
fungerer som behandlere
for enkle tilfeller (som eksempelet ovenfor) definere nye tilpassede typer og servehttp metoder føles litt detaljert. La oss se på en alternativ tilnærming, hvor Vi utnytter Go ‘s http.HandlerFunc
type for å tvinge en normal funksjon til å tilfredsstille Behandlings-grensesnittet.
enhver funksjon som har signaturen func(http.ResponseWriter, *http.Request)
kan konverteres til En HandlerFunc-type. Dette er nyttig fordi HandleFunc-objekter kommer med en innebygd ServeHTTP
metode som – ganske smart og praktisk-utfører innholdet i den opprinnelige funksjonen.
hvis det høres forvirrende ut, kan du prøve å ta en titt på den aktuelle kildekoden. Du vil se at det er en veldig kortfattet måte å gjøre en funksjon tilfredsstille Handler grensesnittet.
la oss reprodusere timeHandler-programmet ved hjelp av denne teknikken:
faktisk konvertere en funksjon Til En HandlerFunc type og deretter legge den til En ServeMux som dette er så vanlig At Go gir en snarvei:mux.HandleFunc
metoden.
dette er hva main()
funksjonen ville ha sett ut hvis vi hadde brukt denne snarveien i stedet:
Mesteparten av tiden bruker en fungerer som en handler Som Dette Fungerer bra. Men det er litt av en begrensning når ting begynner å bli mer komplekse.
du har sikkert lagt merke til at, i motsetning til metoden før, har vi måttet hardcode tidsformatet itimeHandler
– funksjonen. Hva skjer når vi vil sende informasjon eller variabler fra main()
til en handler?
en fin tilnærming er å sette vår handler logikk inn i en lukning, og lukke over variablene vi vil bruke:
timeHandler
funksjonen har nå en litt annen rolle. I stedet for å tvinge funksjonen til en handler (som vi gjorde tidligere), bruker vi nå den til å returnere en handler. Det er to viktige elementer for å gjøre dette arbeidet.
først oppretter den fn
, en anonym funksjon som åpner‐ eller lukker over – format
variabelen som danner en lukning. Uansett hva vi gjør med lukkingen, vil det alltid kunne få tilgang til variablene som er lokale til omfanget det ble opprettet i-som i dette tilfellet betyr at det alltid vil ha tilgang til format
variabelen.
For det andre har vår nedleggelse signaturen func(http.ResponseWriter, *http.Request)
. Som du kanskje husker fra tidligere, betyr dette at vi kan konvertere den til En HandlerFunc-type (slik at den tilfredsstiller Behandlings-grensesnittet). Vår timeHandler
– funksjon returnerer deretter denne konverterte lukkingen.
i dette eksemplet har vi nettopp passert en enkel streng til en handler. Men i en reell søknad kan du bruke denne metoden til å passere databasetilkobling, malkart eller annen kontekst på applikasjonsnivå. Det er et godt alternativ til å bruke globale variabler, og har den ekstra fordelen av å lage ryddige selvstendige håndterere for testing.
du kan også se det samme mønsteret skrevet som:
Eller bruke en implisitt konvertering Til HandlerFunc-typen ved retur:
DefaultServeMux
Du har sikkert sett DefaultServeMux nevnt mange steder, fra De enkleste Hello World-eksemplene til Go-kildekoden.
Det tok meg lang tid å innse at det ikke er noe spesielt. DefaultServeMux er bare en vanlig ol ‘ ServeMux som vi allerede har brukt, som blir instantiert som standard når HTTP-pakken brukes. Her er den relevante linjen Fra Go-kilden:
var DefaultServeMux = NewServeMux()
generelt bør Du ikke bruke DefaultServeMux fordi Det utgjør en sikkerhetsrisiko.
Fordi DefaultServeMux er lagret i en global variabel, kan enhver pakke få tilgang til den og registrere en rute-inkludert eventuelle tredjepartspakker som programmet importerer. Hvis en av disse tredjepartspakkene er kompromittert, kan De bruke DefaultServeMux til å avsløre en ondsinnet behandler på nettet.
så som en tommelfingerregel er det en god ide å unngå DefaultServeMux, og i stedet bruke din egen lokalt scoped ServeMux, som vi har vært så langt. Men hvis du bestemte deg for å bruke den…
HTTP-pakken inneholder et par snarveier for å jobbe Med DefaultServeMux: http. Håndtak og http.HandleFunc. Disse gjør akkurat det samme som deres navnefunksjoner vi allerede har sett på, med forskjellen at de legger til behandlere Til DefaultServeMux i stedet for en du har opprettet.
I Tillegg Vil ListenAndServe falle tilbake til Å bruke DefaultServeMux hvis ingen annen behandler er oppgitt (det vil si at den andre parameteren er satt til nil
).
så som et siste trinn, la oss oppdatere vår timeHandler program for Å bruke DefaultServeMux stedet:
hvis du likte dette blogginnlegget, ikke glem å sjekke ut min nye bok om hvordan du bygger profesjonelle webapplikasjoner med Go!
Følg Meg på twitter @ajmedwards.
alle kodebiter i dette innlegget er gratis å bruke under Mit-Lisensen.