Veebiserverite arendamine Golangi abil - lihtsast keeruliseks

Veebiserverite arendamine Golangi abil - lihtsast keeruliseks

Viis aastat tagasi alustasin ma Gophishi arendamist, see andis vÔimaluse Ôppida Golangi. Ma mÔistsin, et Go on vÔimas keel, mille vÔimalusi tÀiendab arvukalt teeke. Go on universaalne: nÀiteks saab seda kasutada serverirakenduste arendamiseks probleemideta.

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

— Let’s Encrypti kasutamine HTTPS-iks.
— Töötamine API marsruutijana.
— Töötamine middleware'iga.
— Staatiliste failide töötlemine.
— Korralik vĂ€ljalĂŒlitamine.

Skillbox soovitab: Praktiline kursus „Python-arendaja nullist“.

Tuletame meelde: kĂ”igile «Habr» lugejatele – 10 000 rubla allahindlus igale Skillboxi kursusele, kasutades sooduskoodi «Habr».

Tere, maailm!

Veebiserveri loomine Go-s on vĂ€ga kiire. Siin on nĂ€ide toimimisest töötlusest, mis tagastab eelnevalt mainitud „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 leht avada localhost, nĂ€ete kohe teksti „Tere, maailm!“ (muidugi, kui kĂ”ik töötab Ă”igesti).

Edasi kasutame töötlust korduvalt, kuid kÔigepealt vÔtame aega mÔistmiseks, kuidas kÔik toimib.

net/http

NÀites kasutati paketti net/http, see on Go pÔhivahend serverite ja HTTP-kliendi arendamiseks. Koodi mÔistmiseks vaatame kolme olulise elemendi tÀhendust: http.Handler, http.ServeMux ja http.Server.

HTTP-töötlustooted

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

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

Esimeses nĂ€ites kasutatakse abifunktsiooni http.HandleFunc. See ĂŒmbritseb teist funktsiooni, mis omakorda vĂ”tab http.ResponseWriter ja http.Request'i ServeHTTP-s.

TeisisĂ”nu, töötlejad Golangis esindavad ĂŒhtset liidest, mis pakub programmeerijale palju vĂ”imalusi. NĂ€iteks on middleware rakendatud lĂ€bi töötleja, kus ServeHTTP teeb esmalt midagi ja seejĂ€rel kutsub teise töötleja ServeHTTP meetodi.

Nagu eelpool öeldud, töötlejad koostavad lihtsalt vastuseid pÀringutele. Kuid millist töötlejat tuleks kasutada konkreetsel hetkel?

PĂ€ringute marsruutimine

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

Kui on vajalik keerulise marsruutimise tugi, on parem kasutada kolmandate osapoolte raamatukogusid. MĂ”ned kĂ”ige arenenumad on: gorilla/mux ja go-chi/chi, need raamatukogud vĂ”imaldavad rakendada vahepealseid töötlemisi ilma eriliste probleemideta. Nende abil on vĂ”imalik seadistada wildcards-marsruutimist ja lahendada mitmeid muid ĂŒlesandeid. Nende eeliseks on ĂŒhilduvus standardsete HTTP-töötlejatega. Tulemuseks on, et saate kirjutada lihtsa koodi, millel on tulevikus muudetava koodi vĂ”imalus.

Töökeeruliste raamistikudega tavaliselt nÔuab ebatavalisi lahendusi, mis oluliselt keerukamaks muudab standardsete töötlejate kasutamise. Enamikule rakendustele piisab vaikimisi raamatukogu ja lihtsa ruuteri kombinatsioonist.

PÀringute töötlemine

Lisaks on meil vajalik komponent, mis „kuulab” sissetulevaid ĂŒhendusi ja suunab kĂ”ik pĂ€ringud Ă”igele töötlejale. Selle ĂŒlesandega saab hĂ”lpsasti hakkama http.Server.

Allpool on nĂ€idatud, et server vastutab kĂ”igi ĂŒlesannete eest, mis on seotud ĂŒhenduste töötlemisega. See hĂ”lmab nĂ€iteks TLS-protokolli tööd. http.ListenAndServe'i kutsumise rakendamiseks kasutatakse standardset HTTP-serverit.

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

Let’s Encrypti lisamine

Vaikimisi töötab meie rakendus HTTP-protokolli abil, kuid soovitatakse kasutada HTTPS-protokolli. Go-s saab seda teha probleemideta. Kui olete saanud sertifikaadi ja privaatvÔtme, piisab, kui mÀÀrata ListenAndServeTLS koos Ôige sertifikaadi ja vÔtmefailiga.

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 meetodit autocert.NewListener koos http.Serve'iga. Meetod vÔimaldab saada ja uuendada TLS-sertifikaate, samal ajal kui HTTP-server töötleb pÀringuid:

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

Kui avame brauseris example.com, siis saame HTTPS-reaktsiooni «Tere, maailm!».

Kui vajate pÔhjalikumat seadistamist, siis tasub kasutada autocert.Manager'i. SeejÀrel loome oma http.Server'i instantsi (kuni praeguseni oleme kasutanud vaikeseadet) ja lisame halduri TLSConfig'i serverisse:

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 kogu HTTPS-toe rakendamiseks automaatse sertifikaadi uuendamisega.

Mitte-standardsete marsruutide lisamine

Vaikimisi marsruuter, mis on kaasatud standardteekidesse, on hea, kuid vÀga lihtne. Enamikes rakendustes on vajalik keerulisem marsruutimine, sealhulgas pesakonnad ja wildcard-marsruudid vÔi ƥabloonide ja teeparameetrite seadistamise protseduur.

Selles olukorras tasub kasutada pakette gorilla/mux ja go-chi/chi. Viimasega Ă”pime me töötama — allpool on nĂ€ide.

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

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

Seame marsruutidele api/vq prefiksi peafailis.

Saame seejÀrel selle meie peamisse marsruuterisse lisada api/v1/ prefiksi all tagasi meie pÔhitarvutis:

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

Töötamine keeruliste marsruutidega Go-s vÔimaldab lihtsustada suure keeruliste rakenduste haldust.

Töötamine middleware'iga

Vahepealse töötlemise korral kasutatakse ĂŒhe HTTP-kĂ€itja mĂ€hkimist teise, mis vĂ”imaldab kiiresti teha autentimist, tihendamist, logimist ja mĂ”ned muud funktsioonid.

NÀiteks vaatame http.Handler'i liidest, mille abil kirjutame kasutajate autentimisega kÀitja.

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Àitame originaalkÀitjat
        next.ServeHTTP(w, r)
    })
}

On olemas kolmanda osapoole marsruutijad, nagu chi, mis vÔimaldavad vahepealse töötlemise funktsionaalsust laiendada.

Töötamine staatiliste failidega

Go standardteek sisaldab vÔimalusi staatilise sisu kÀsitlemiseks, sealhulgas pilte ja JavaScripti ja CSS-faile. Neile pÀÀseb juurde http.FileServer'i funktsiooni kaudu. See tagastab kÀitja, mis edastab faile kindlast kataloogist.

func NewRouter() http.Handler {
    router := chi.NewRouter()
    r.Get("/{name}", HelloName)
 
// Kuidas seadistada staatiliste failide jagamist
staticPath, _ := filepath.Abs("../../static/")
fs := http.FileServer(http.Dir(staticPath))
    router.Handle("/*", fs)
    
    return r

Oluline on meeles pidada, et http.Dir kuvab kausta sisu vaid juhul, kui seal pole pÔhifaili index.html. Sellisel juhul tuleks kausta kompromiteerimise vÀltimiseks kasutada paketti indeksimata.

Korralik sulgemine

Go-s on olemas ka selline funktsioon nagu HTTP-serveri korralik sulgemine. Seda saab teha Shutdown() meetodi abil. Server kĂ€ivitub goroutines ja seejĂ€rel kuulatakse signaali katkestamiseks. 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 on vĂ”imas keel, millel on quasi-ĂŒksne standardteek. Selle vaikimisi vĂ”imalused on ulatuslikud, ja neid saab tugevdada liideste abil — see vĂ”imaldab arendada tĂ”eliselt usaldusvÀÀrseid HTTP-servereid.

Skillbox soovitab:

Allikas: habr.com

Osta usaldusvÀÀrne hostimine veebilehtede jaoks DDoS-i kaitsega, VPS VDS serverid đŸ”„ Osta usaldusvÀÀrne hostimine veebilehtede jaoks DDoS-i kaitsega, VPS VDS serverid | ProHoster