Veebiserverite arendamine Golangis — lihtsast keeruliseni

Veebiserverite arendamine Golangis — lihtsast keeruliseni

Viis aastat tagasi alustasin Gophishi arendamist, see andis vÔimaluse Golangi Ôppimiseks. MÔistsin, et Go on vÔimas keel, mille vÔimalusi tÀiendavad mitmed teegid. Go on universaalne: selle abil on lihtne arendada serverirakendusi.

See artikkel on pĂŒhendatud Go-s serveri kirjutamisele. Alustame lihtsatest asjadest, nagu "Tere maailm!", ja lĂ”petame rakendusega, millel on jĂ€rgmised vĂ”imalused:

— Let’s Encrypti kasutamine HTTPS-i jaoks.
— Töö API marsruutijana.
— Töö middleware’iga.
— Statiliste failide töötlemine.
— Korralik lĂ”petamine.

Skillbox soovitab: Praktiline kursus „Python-arendaja algusest peale“.

Tuletame meelde: kĂ”igile «Habra» lugejatele — 10 000 rubla soodustus, kui registreerite end Skillboxi mis tahes kursusele promokoodi «Habr» abil.

Tere, maailm!

Veebiserveri loomine Go-s on vÀga kiire. Siin on nÀide töötlejast, mis naaseb lubatud "Tere, maailm!".

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

PÀrast seda, kui rakendus kÀivitada ja lehte avada localhost, nÀete kohe teksti "Tere, maailm!" (loomulikult, kui kÔik töötab Ôigesti).

Edasi kavatseme töötlejat mitu korda kasutada, kuid esmalt mĂ”istame, kuidas kĂ”ik on ĂŒles seatud.

net/http

NÀites kasutati paketti net/http, mis on Go-s peamine vahend serverite ja HTTP-kliendi arendamiseks. Koodi parema mÔistmise nimel tutvume kolme olulise elemendi tÀhendusega: http.Handler, http.ServeMux ja http.Server.

HTTP töötlejad

Kui saame pĂ€ringu, analĂŒĂŒsib töötleja selle ja vormib vastuse. Go-s on töötlejad rakendatud jĂ€rgmiselt:

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

Esimeses nĂ€ites kasutatakse abifunktsiooni http.HandleFunc. See ĂŒmbritseb teise funktsiooni, mis omakorda vĂ”tab vastu http.ResponseWriter ja http.Request funktsioonis ServeHTTP.

Teisiti öeldes, on töötlejad Golangis esitatud ĂŒhtse liidesena, mis annab programmeerijale palju vĂ”imalusi. NĂ€iteks rakendatakse middleware töötleja kaudu, kus ServeHTTP teeb kĂ”igepealt midagi ja seejĂ€rel kutsub teise töötleja ServeHTTP meetodi.

Nagu juba mainitud, kujundavad töötlejad lihtsalt vastuseid pÀringutele. Kuid millist töötlejat on konkreetsel hetkel vaja kasutada?

PĂ€ringute marsruutimine

Õige valiku tegemiseks kasutage HTTP-multiplexerit. Mitmes raamatukogus nimetatakse seda muxeriks vĂ”i ruuteriks, kuid tĂ”epoolest on need kĂ”ik ĂŒhesugused. Multiplexer'i funktsioon on analĂŒĂŒsida pĂ€ringu teed ja valida vastav töötleja.

Kui on vajalik keeruka marsruutimise tugi, siis on parem kasutada kolmandate osapoolte raamatukogusid. Üks kĂ”ige arenenumatest on gorilla/mux ja go-chi/chi, need raamatukogud vĂ”imaldavad hĂ”lpsasti rakendada vahepealse töötlemise lahendusi. Nende abil saate seadistada wildcard-marsruutimise ja teisi ĂŒlesandeid. Nende eeliseks on ĂŒhilduvus standardsete HTTP-töötlejatega. Tulemusena saate kirjutada lihtsa koodi, millel on vĂ”imalus seda tulevikus kohandada.

Töötamine keerukate raamistikudega tavapÀrases olukorras nÔuab mitte vÀga standardseid lahendusi, mis oluliselt raskendab vaikimisi töötlejate kasutamist. Enamik rakendusi saavad hakkama vaikimisi raamatukogu ja lihtsa ruuteriga.

PÀringute töötlemine

Lisaks vajame komponenti, mis "kuulab" sisse tulevaid ĂŒhendusi ja suunab kĂ”ik pĂ€ringud Ă”ige töötleja juurde. Selle ĂŒlesande tĂ€idab probleemideta http.Server.

Allpool on nĂ€idatud, et server vastutab kĂ”igi ĂŒlesannete eest, mis on seotud ĂŒhenduste töötlemisega. NĂ€iteks toimub siin TLS-protokolli töötlemine. http.ListenAndServeri rakendamiseks kasutatakse standardset HTTP-serverit.

NĂŒĂŒd vaatame keerulisemaid nĂ€iteid.

Lisamine Let’s Encrypt

Vaikimisi töötab meie rakendus HTTP-protokolli kaudu, kuid on soovitatav kasutada HTTPS-protokolli. Go-s on see lihtne. Kui olete saanud sertifikaadi ja privaatvÔtme, piisab, kui kutsuda esile ListenAndServeTLS, osutades Ôigele sertifikaadi ja vÔtme failile.

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

Alati on vÔimalik paremini teha.

Let’s Encrypt pakub tasuta sertifikaate automaatse uuendamise vĂ”imalusega. Teenuse kasutamiseks on vajalik pakett autocert.

Lihtsaim viis selle seadistamiseks on kasutada autocert.NewListener meetodit koos http.Serve'iga. See meetod vÔimaldab hankida ja uuendada TLS-sertifikaate, samal ajal kui HTTP-server kÀsitleb pÀringuid:

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

Kui avame brauseris example.com, saame HTTPS-vastuse „Hello, world!”.

Kui vajame tÀiendavat seadistamist, on soovitatav kasutada autocert.Manager haldurit. SeejÀrel loome oma http.Server eksemplari (kuni siiamaani kasutasime vaikeversiooni) ja lisame halduri serveri TLSConfig'i:

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("", "")

See on lihtne viis tÀieliku HTTPS toe rakendamiseks koos automaatse sertifikaadi uuendamisega.

Kohandatud marsruutide lisamine

Standardteekide vaikemarsruuter, mis on kaasatud standardbiblioteeki, on hea, kuid vÀga lihtne. Enamikus rakendustes on vaja keerukamat marsruutimist, sealhulgas pesamarsruute ja wildcard-marsruute vÔi samuti mallide ja marsruutide parameetrite mÀÀramist.

Selles olukorras on soovitatav kasutada pakette gorilla/mux ja go-chi/chiMeie viimane teema on see, kuidas töötada . Allpool on nÀide.

Antud on fail api/v1/api.go, mis sisaldab marsruute meie API-le:

/ 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
}

Seadistame marsruutide eelprefiksiks api/vq peafailis.

Saame selle mountida meie peamise marsruudile api/v1/ prefiksi alla tagasi meie pÔhiÀpis:

// 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())

Go-s keeruliste marsruutidega töötamise lihtsus vÔimaldab lihtsustada suuremate keeruliste rakenduste haldamist.

Töötamine vahekihiga

Vahekihtide töötamisel ĂŒmbritsetakse ĂŒhte HTTP-kĂ€sitlejat teisega, mis vĂ”imaldab kiiresti teostada autentimist, tihendamist, logimist ja mĂ”ningaid muid funktsioone.

NÀiteks vaatame http.Handler liidest, millega kirjutame HTTP-kÀsitleja, mis teostab teenuse kasutajate autentimist.

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
        }
        // Eeldades, et autentimine on lÀbitud, kÀivita algne kÀsitleja
        next.ServeHTTP(w, r)
    })
}

On ka kolmandate osapoolte marsruuterid, nagu chi, mis vÔimaldavad laiendada vahekihitöötluse funktsionaalsust.

Töötamine staatiliste failidega

Go standardraamatukogus on olemas vÔimalused staatilise sisu töötlemiseks, sealhulgas piltide ning JavaScripti ja CSS-failide jaoks. Neile pÀÀseb juurde funktsiooni http.FileServer kaudu, mis tagastab töötleja, mis jagab faile mÀÀratud kataloogist.

func NewRouter() http.Handler {
    router := chi.NewRouter()
    r.Get("/{name}", HelloName)

// Staatiliste failide jagamise seadistus
staticPath, _ := filepath.Abs("../../../static/")
fs := http.FileServer(http.Dir(staticPath))
    router.Handle("/*", fs)

    return r

Oluline on meeles pidada, et http.Dir kuvab katalooge ainult siis, kui seal ei ole pÔhifaili index.html. Sellisel juhul, et vÀltida katalooge riskimist, tuleks kasutada paketti unindexed.

Korrektselt töö lÔpetamine

Go-s on olemas ka selline funktsioon nagu HTTP-serveri korrektselt töö lĂ”petamine. Seda saab teha meetodi Shutdown() abil. Server kĂ€ivitatakse goroutine'is ning seejĂ€rel kuulatakse signaali katkestamise vastuvĂ”tmiseks. Nii varsti kui signaal on saadud, lĂŒlitatakse server vĂ€lja, kuid mitte kohe, vaid mĂ”ne sekundi pĂ€rast.

handler := server.NewRouter()
srv := &http.Server{
    Handler: handler,
}
 
go func() {
srv.Serve(autocert.NewListener(domains...))
}()
 
// Oota katkestust
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt)
<-c
 
// Proovi korralikku sulgemist
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
srv.Shutdown(ctx)

KokkuvÔtteks

Go — vĂ”imas keel, millel on praktiliselt universaalne standardraamatukogu. Selle vaikimisi vĂ”imalused on ĂŒsna laiad, ja neid saab tugevdada liideste abil — see vĂ”imaldab arendada tĂ”eliselt usaldusvÀÀrseid HTTP-servereid.

Skillbox soovitab:

Allikas: habr.com

Osta usaldusvÀÀrne veebihosting DDoS kaitsega, VPS VDS serverid đŸ”„ Osta usaldusvÀÀrne veebihosting DDoS kaitsega, VPS VDS serverid | ProHoster