Þróun vefþjóna í Golang - frá einföldum til flókinna

Þróun vefþjóna í Golang - frá einföldum til flókinna

Fyrir fimm árum byrjaði ég þróa Gophish, þetta gaf tækifæri til að læra Golang. Ég áttaði mig á því að Go er öflugt tungumál, bætt við mörg bókasöfn. Go er fjölhæfur: sérstaklega er hægt að nota það til að þróa forrit á netþjóni án vandræða.

Þessi grein fjallar um að skrifa netþjón í Go. Byrjum á einföldum hlutum eins og „Halló heimur!“ og endum með forriti með eftirfarandi getu:

- Notkun Let's Encrypt fyrir HTTPS.
— Að vinna sem API leið.
— Að vinna með millihugbúnað.
— Vinnsla á kyrrstæðum skrám.
— Rétt lokun.

Skillbox mælir með: Verklegt námskeið „Python verktaki frá grunni“.

Við minnum á: fyrir alla Habr lesendur - 10 rúblur afsláttur þegar þú skráir þig á hvaða Skillbox námskeið sem er með því að nota Habr kynningarkóðann.

Halló heimur!

Þú getur búið til vefþjón í Go mjög fljótt. Hér er dæmi um notkun stjórnanda sem skilar „Halló, heimur!“ sem lofað var hér að ofan.

package main
 
import (
"fmt"
"net/http"
)
 
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello World!")
})
http.ListenAndServe(":80", nil)
}

Eftir þetta, ef þú keyrir forritið og opnar síðuna localhost, þá muntu strax sjá textann „Halló, heimur!“ (ef allt virkar rétt, auðvitað).

Við munum nota stjórnandann mörgum sinnum síðar, en fyrst skulum við skilja hvernig allt virkar.

net/http

Dæmið notaði pakkann net/http, það er aðal tólið í Go til að þróa bæði netþjóna og HTTP viðskiptavini. Til að skilja kóðann skulum við skilja merkingu þriggja mikilvægra þátta: http.Handler, http.ServeMux og http.Server.

HTTP meðhöndlarar

Þegar við fáum beiðni greinir stjórnandinn hana og býr til svar. Handlarar í Go eru útfærðir sem hér segir:

type Handler interface {
        ServeHTTP(ResponseWriter, *Request)
}

Fyrsta dæmið notar http.HandleFunc hjálparaðgerðina. Það vefur aðra aðgerð, sem aftur tekur http.ResponseWriter og http.Request inn í ServeHTTP.

Með öðrum orðum, stjórnendur í Golang eru settir fram í einu viðmóti, sem gefur forritaranum marga möguleika. Svo, til dæmis, er millihugbúnaður útfærður með því að nota meðhöndlun, þar sem ServeHTTP gerir fyrst eitthvað og kallar síðan ServeHTTP aðferð annars meðhöndlunar.

Eins og getið er hér að ofan búa umsjónarmenn einfaldlega til svör við beiðnum. En hvaða tiltekna meðhöndlun ætti að nota á tilteknum tímapunkti?

Biðja um leið

Til að velja rétt skaltu nota HTTP multiplexer. Í mörgum bókasöfnum er það kallað muxer eða router, en þau eru öll sami hluturinn. Hlutverk multiplexersins er að greina beiðnislóðina og velja viðeigandi meðhöndlun.

Ef þú þarft stuðning við flókna leið, þá er betra að nota þriðja aðila bókasöfn. Sumir af þeim fullkomnustu - górilla/mux и go-chi/chi, þessi bókasöfn gera það mögulegt að innleiða millivinnslu án vandræða. Með hjálp þeirra geturðu stillt beina með algildisstafi og framkvæmt fjölda annarra verkefna. Kostur þeirra er eindrægni við venjulega HTTP meðhöndlun. Fyrir vikið geturðu skrifað einfaldan kóða sem hægt er að breyta í framtíðinni.

Vinna með flókna ramma í venjulegum aðstæðum mun krefjast óstaðlaðra lausna og það flækir verulega notkun sjálfgefna. Til að búa til langflest forrit dugar sambland af sjálfgefna bókasafninu og einföldum beini.

Vinnsla fyrirspurna

Að auki þurfum við íhlut sem mun „hlusta“ á komandi tengingar og beina öllum beiðnum til rétts meðhöndlunar. http.Server getur auðveldlega séð um þetta verkefni.

Eftirfarandi sýnir að þjónninn ber ábyrgð á öllum verkefnum sem tengjast tengingarvinnslu. Þetta virkar til dæmis með TLS samskiptareglum. Til að innleiða http.ListenAndServer símtalið er venjulegur HTTP netþjónn notaður.

Nú skulum við líta á flóknari dæmi.

Bætir við Let's Encrypt

Sjálfgefið er að forritið okkar keyrir yfir HTTP samskiptareglur, en mælt er með því að nota HTTPS samskiptareglur. Þetta er hægt að gera án vandræða í Go. Ef þú hefur fengið vottorð og einkalykil, þá er nóg að skrá ListenAndServeTLS með réttum skilríkjum og lykilskrám.

http.ListenAndServeTLS(":443", "cert.pem", "key.pem", nil)

Það er alltaf hægt að gera betur.

Skulum dulrita veitir ókeypis skírteini með sjálfvirkri endurnýjun. Til þess að nota þjónustuna þarftu pakka autocert.

Auðveldasta leiðin til að stilla það er að nota autocert.NewListener aðferðina ásamt http.Serve. Aðferðin gerir þér kleift að fá og uppfæra TLS vottorð á meðan HTTP þjónninn vinnur úr beiðni:

http.Serve(autocert.NewListener("example.com"), nil)

Ef við opnum í vafranum example.com, munum við fá HTTPS svar „Halló, heimur!“

Ef þú þarft ítarlegri uppsetningu, þá ættir þú að nota autocert.Manager stjórnanda. Síðan búum við til okkar eigið http.Server dæmi (þangað til nú notuðum við það sjálfgefið) og bætum stjórnandanum við TLSConfig þjóninn:

m := &autocert.Manager{
Cache:      autocert.DirCache("golang-autocert"),
Prompt:     autocert.AcceptTOS,
HostPolicy: autocert.HostWhitelist("example.org", "www.example.org"),
}
server := &http.Server{
    Addr:      ":443",
    TLSConfig: m.TLSConfig(),
}
server.ListenAndServeTLS("", "")

Þetta er auðveld leið til að innleiða fullan HTTPS stuðning með sjálfvirkri endurnýjun vottorða.

Bætir við sérsniðnum leiðum

Sjálfgefinn leið sem fylgir venjulegu bókasafninu er góður, en hann er mjög grunnur. Flest forrit krefjast flóknari leiðar, þar á meðal hreiðra og algildisleiða, eða aðferð til að stilla slóðamynstur og færibreytur.

Í þessu tilfelli er það þess virði að nota pakka górilla/mux и go-chi/chi. Við munum læra hvernig á að vinna með hið síðarnefnda - dæmi er sýnt hér að neðan.

Gefin er skráin api/v1/api.go sem inniheldur leiðir fyrir API okkar:

/ HelloResponse is the JSON representation for a customized message
type HelloResponse struct {
Message string `json:"message"`
}
 
// HelloName returns a personalized JSON message
func HelloName(w http.ResponseWriter, r *http.Request) {
name := chi.URLParam(r, "name")
response := HelloResponse{
Message: fmt.Sprintf("Hello %s!", name),
}
jsonResponse(w, response, http.StatusOK)
}
 
// NewRouter returns an HTTP handler that implements the routes for the API
func NewRouter() http.Handler {
r := chi.NewRouter()
r.Get("/{name}", HelloName)
return r
}

Við stillum api/vq forskeytið fyrir leiðir í aðalskránni.

Við getum síðan tengt þetta á aðalbeini okkar undir api/v1/ forskeytinu aftur í aðalforritinu okkar:

// NewRouter returns a new HTTP handler that implements the main server routes
func NewRouter() http.Handler {
router := chi.NewRouter()
    router.Mount("/api/v1/", v1.NewRouter())
    return router
}
http.Serve(autocert.NewListener("example.com"), NewRouter())

Auðvelt Go að vinna með flóknar leiðir gerir það mögulegt að einfalda uppbyggingu og viðhald stórra, flókinna forrita.

Að vinna með millibúnað

Sviðsetning felur í sér að vefja einn HTTP meðhöndlun með öðrum, sem gerir það mögulegt að framkvæma fljótt auðkenningu, þjöppun, skráningu og nokkrar aðrar aðgerðir.

Sem dæmi skulum við skoða http.Handler viðmótið; við munum nota það til að skrifa meðhöndlun sem auðkennir þjónustunotendur.

func RequireAuthentication(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        if !isAuthenticated(r) {
            http.Redirect(w, r, "/login", http.StatusTemporaryRedirect)
            return
        }
        // Assuming authentication passed, run the original handler
        next.ServeHTTP(w, r)
    })
}

Það eru beinir frá þriðja aðila, eins og chi, sem gera þér kleift að auka virkni millihugbúnaðar.

Vinna með truflanir skrár

Go staðalsafnið inniheldur möguleika til að vinna með kyrrstætt efni, þar á meðal myndir, JavaScript og CSS skrár. Hægt er að nálgast þær í gegnum http.FileServer aðgerðina. Það skilar meðhöndlun sem þjónar skrám úr tiltekinni möppu.

func NewRouter() http.Handler {
    router := chi.NewRouter()
    r.Get("/{name}", HelloName)
 
// Настройка раздачи статических файлов
staticPath, _ := filepath.Abs("../../static/")
fs := http.FileServer(http.Dir(staticPath))
    router.Handle("/*", fs)
    
    return r

Það er örugglega þess virði að muna að http.Dir sýnir innihald möppunnar ef hún inniheldur ekki aðal index.html skrána. Í þessu tilviki, til að koma í veg fyrir að skrárinn sé í hættu, ættir þú að nota pakkann unindexed.

Rétt lokun

Go hefur einnig eiginleika sem kallast þokkafull lokun á HTTP netþjóninum. Þetta er hægt að gera með því að nota Shutdown() aðferðina. Miðlarinn er ræstur í goroutine og síðan er hlustað á rásina til að fá truflunarmerki. Um leið og merki er móttekið slekkur þjónninn á sér, en ekki strax, heldur eftir nokkrar sekúndur.

handler := server.NewRouter()
srv := &http.Server{
    Handler: handler,
}
 
go func() {
srv.Serve(autocert.NewListener(domains...))
}()
 
// Wait for an interrupt
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt)
<-c
 
// Attempt a graceful shutdown
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
srv.Shutdown(ctx)

Sem niðurstaða

Go er öflugt tungumál með næstum alhliða stöðluðu bókasafni. Sjálfgefin hæfileiki þess er mjög breiður og hægt er að auka þá með viðmóti - þetta gerir þér kleift að þróa sannarlega áreiðanlega HTTP netþjóna.

Skillbox mælir með:

Heimild: www.habr.com

Bæta við athugasemd