a Recap kérelem kezelése Go
feldolgozása HTTP kérések Go elsősorban két dolog: ServeMuxes és kezelők.
a ServeMux lényegében egy HTTP kérés router (vagy multiplexor). Összehasonlítja a beérkező kéréseket az előre definiált URL-útvonalak listájával, és meghívja az elérési út társított kezelőjét, amikor egyezést talál.
a kezelők felelősek a válasz fejlécek és testek írásáért. Szinte minden objektum lehet kezelő, amennyiben megfelel a http.Handler
felületnek. Laikus értelemben ez egyszerűen azt jelenti, hogy rendelkeznie kell egy ServeHTTP
módszerrel a következő aláírással:
ServeHTTP(http.ResponseWriter, *http.Request)
A GO HTTP csomagja néhány funkcióval rendelkezik, hogy közös kezelőket generáljon, például FileServer
NotFoundHandler
és RedirectHandler
. Kezdjük egy egyszerű, de kitalált példával:
lépjünk át gyorsan ezen:
- a
main
funkció ahttp.NewServeMux
funkció ahhoz, hogy hozzon létre egy üres servemux. - ezután a
http.RedirectHandler
függvényt használjuk egy új kezelő létrehozásához. Ez a 307 kezelő átirányítja az összes beérkező kérést ahttp://example.org
címre. - ezután a
mux.Handle
függvényt használjuk, hogy regisztráljuk ezt az új ServeMux-nál, így az összes bejövő kérés kezelőjeként működik az URL elérési útjával/foo
. - végül létrehozunk egy új szervert, és elkezdjük hallgatni a bejövő kéréseket a
http.ListenAndServe
funkcióval, átadva a ServeMux-ot, hogy megfeleljen a kéréseknek.
menj előre, és futtassa az alkalmazást:
és látogasson elhttp://localhost:3000/foo
a böngészőben. Meg kell találni, hogy a kérés lesz sikeresen átirányítva.
a sasszemű lehet, hogy észrevett valami érdekeset: a ListenAndServe függvény aláírása ListenAndServe(addr string, handler Handler)
, de a ServeMux-ot adtuk át második paraméterként.
ezt azért tudtuk megtenni, mert a ServeMux típusnak van egy ServeHTTP
metódusa is, ami azt jelenti, hogy ez is kielégíti a kezelőfelületet.
számomra ez leegyszerűsíti a dolgokat gondolni egy ServeMux, mint csak, hogy egy különleges fajta kezelő, amely ahelyett, hogy a válasz maga továbbítja a kérést egy második kezelő. Ez nem annyira ugrás, mint amilyennek először hangzik – a kezelők összekapcsolása meglehetősen általános a Go-ban.
egyéni kezelők
hozzunk létre egy egyéni kezelőt, amely az aktuális helyi idővel válaszol egy adott formátumban:
a pontos kód itt nem túl fontos.
csak az számít igazán, hogy van egy objektumunk (ebben az esetben ez egy timeHandler
struct, de lehet string vagy függvény, vagy bármi más is), és végrehajtottunk egy módszert az aláírással ServeHTTP(http.ResponseWriter, *http.Request)
rajta. Ez minden, amire szükségünk van, hogy egy kezelő legyen.
beágyazzuk ezt egy konkrét példába:
a main
függvényben a timeHandler
pontosan ugyanúgy inicializáltuk a timeHandler
szimbólum a mutató megjelenítéséhez. Ezután az előző példához hasonlóan a mux.Handle
függvényt használjuk ennek regisztrálására a ServeMux-nál.
Most, amikor futtatjuk az alkalmazást, a ServeMux minden /time
kérést továbbít a timeHandler.ServeHTTP
módszerünkre.
Menj és próbáld ki: http://localhost:3000/time
.
figyeljük meg, hogy mi is könnyen újra a timeHandler
több útvonalon:
kezelőként működik
egyszerű esetekben (például a fenti példában) új egyéni típusok és servehttp módszerek meghatározása kissé bőbeszédű. Nézzünk meg egy alternatív megközelítést, ahol kihasználjuk a Go http.HandlerFunc
típusát, hogy egy normál funkciót kényszerítsünk a kezelőfelület kielégítésére.
minden olyan függvény, amelynek aláírása func(http.ResponseWriter, *http.Request)
átalakítható HandlerFunc típusra. Ez azért hasznos, mert a HandleFunc objektumok beépített ServeHTTP
metódussal rendelkeznek, amely – meglehetősen ügyesen és kényelmesen – végrehajtja az eredeti függvény tartalmát.
Ha ez zavarónak hangzik, próbálja meg megnézni a megfelelő forráskódot. Látni fogja, hogy ez egy nagyon tömör módja annak, hogy egy funkció kielégítse a kezelőfelületet.
reprodukáljuk a timeHandler alkalmazást ezzel a technikával:
valójában egy függvény konvertálása HandlerFunc típusra, majd hozzáadása egy ilyen ServeMux-hoz olyan gyakori, hogy a Go parancsikont biztosít: a mux.HandleFunc
módszer.
így nézett volna ki a main()
függvény, Ha ezt a parancsikont használtuk volna:
a legtöbb esetben egy funkció, mint egy kezelő, mint ez jól működik. De van egy kis korlátozás, amikor a dolgok bonyolultabbá válnak.
valószínűleg észrevette, hogy a korábbi módszerrel ellentétben az időformátumot a timeHandler
függvényben kellett kódolni. Mi történik, ha információt vagy változókat akarunk átadni a main()
– ből egy kezelőnek?
egy ügyes megközelítés az, hogy a kezelő logikánkat bezárjuk, és bezárjuk a használni kívánt változókat:
a timeHandler
funkció most már egy finoman más szerepet. Ahelyett, hogy a függvényt kezelővé kényszerítenénk (mint korábban tettük), most egy kezelő visszaadására használjuk. Két kulcsfontosságú eleme van ennek a munkának.
először létrehozza a fn
névtelen függvényt, amely hozzáfér a &kötőjel; vagy bezárja a format
változót, amely lezárást képez. Függetlenül attól, hogy mit csinálunk a bezárással, mindig képes lesz elérni azokat a változókat, amelyek lokálisak ahhoz a hatókörhöz, amelyben létrehozták – ami ebben az esetben azt jelenti, hogy mindig hozzáférhet a format
változóhoz.
másodszor a lezárásunk aláírással rendelkezik func(http.ResponseWriter, *http.Request)
. Mint korábban emlékszel, ez azt jelenti, hogy átalakíthatjuk HandlerFunc típusba (úgy, hogy kielégítse a kezelő felületet). A timeHandler
függvény ezt az átalakított zárást adja vissza.
ebben a példában éppen egy egyszerű karakterláncot adtunk át egy kezelőnek. De egy valós alkalmazásban ezt a módszert használhatja adatbázis-kapcsolat, sablontérkép vagy bármely más alkalmazásszintű kontextus átadására. Ez egy jó alternatíva a globális változók használatához, és további előnye, hogy tiszta, önálló kezelőket készít a teszteléshez.
ugyanazt a mintát is láthatja, mint:
vagy implicit konverziót használ a HandlerFunc típusra visszatéréskor:
A DefaultServeMux
valószínűleg láttad DefaultServeMux említett sok helyen, a legegyszerűbb Hello World példák a GO forráskód.
hosszú időbe telt, mire rájöttem, hogy ez nem valami különleges. A DefaultServeMux csak egy egyszerű ol ‘ ServeMux, mint amit már használunk, amely alapértelmezés szerint példányosul a HTTP csomag használatakor. Itt van a megfelelő sor a Go forrásból:
var DefaultServeMux = NewServeMux()
általában nem szabad használni a DefaultServeMux-ot, mert biztonsági kockázatot jelent.
mivel a DefaultServeMux globális változóban van tárolva, bármely csomag hozzáférhet hozzá és regisztrálhat egy útvonalat – beleértve az alkalmazás által importált harmadik féltől származó csomagokat is. Ha az egyik ilyen harmadik féltől származó csomag veszélybe kerül, akkor a DefaultServeMux segítségével rosszindulatú kezelőt tehet ki az internetre.
tehát ökölszabályként jó ötlet elkerülni a DefaultServeMux – ot, ehelyett a saját helyi hatókörű ServeMux-ot használja, mint eddig. De ha mégis úgy dönt, hogy használja…
a HTTP csomag néhány parancsikont tartalmaz a DefaultServeMux: http használatához.Fogantyú és http.HandleFunc. Ezek pontosan ugyanazt teszik, mint a névrokon funkcióik, amelyeket már megnéztünk, azzal a különbséggel, hogy kezelőket adnak a Defaultservemuxhoz az Ön által létrehozott helyett.
ezenkívül a ListenAndServe visszatér a DefaultServeMux használatához, ha nincs más kezelő (vagyis a második paraméter értéke nil
).
tehát utolsó lépésként frissítsük a timeHandler alkalmazást a DefaultServeMux helyett:
Ha tetszett ez a blogbejegyzés, ne felejtsd el, hogy nézd meg az új könyv arról, hogyan kell építeni professzionális webes alkalmazások Go!
Kövess a Twitteren @ajmedwards.
Az ebben a bejegyzésben szereplő összes kódrészlet szabadon használható az MIT licenc alatt.