Veebiserveri arendamine Golangis - lihtsast keerukani

Veebiserveri arendamine Golangis - lihtsast keerukani

Viis aastat tagasi alustasin arendada Gophishit, see andis võimaluse õppida golangi. Sain aru, et Go on võimas keel, mida täiendavad paljud raamatukogud. Go on mitmekülgne: eelkõige saab seda probleemideta kasutada serveripoolsete rakenduste arendamiseks.

See artikkel räägib serveri kirjutamisest Go-s. Alustame lihtsatest asjadest, nagu "Tere maailm!" ja lõpetame rakendusega, millel on järgmised võimalused:

- Let's Encrypti kasutamine HTTPS-i jaoks.
— API-ruuterina töötamine.
— Vahevaraga töötamine.
— Staatiliste failide töötlemine.
— Õige väljalülitamine.

Skillbox soovitab: Praktiline kursus "Pythoni arendaja nullist".

Tuletame meelde: kõigile "Habr" lugejatele - allahindlus 10 000 rubla, kui registreerute mis tahes Skillboxi kursusele, kasutades sooduskoodi "Habr".

Tere, Maailm!

Go-s saate veebiserveri luua väga kiiresti. Siin on näide töötleja kasutamisest, mis tagastab ülalpool lubatud "Tere, maailm!".

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

Pärast seda, kui käivitate rakenduse ja avate lehe localhost, siis näete kohe teksti "Tere, maailm!" (muidugi, kui kõik töötab õigesti).

Hiljem kasutame töötlejat mitu korda, kuid kõigepealt mõistame, kuidas kõik töötab.

net/http

Näidis kasutas paketti net/http, on see Go peamine tööriist nii serverite kui ka HTTP-klientide arendamiseks. Koodi mõistmiseks mõistame kolme olulise elemendi tähendust: http.Handler, http.ServeMux ja http.Server.

HTTP töötlejad

Kui saame päringu, analüüsib töötleja seda ja genereerib vastuse. Go töötlejaid rakendatakse järgmiselt.

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

Esimene näide kasutab abifunktsiooni http.HandleFunc. See mähib teise funktsiooni, mis omakorda võtab http.ResponseWriter ja http.Request serverisse ServeHTTP.

Teisisõnu, Golangi töötlejad on esitatud ühes liideses, mis annab programmeerijale palju võimalusi. Nii et näiteks vahevara realiseeritakse käitleja abil, kus ServeHTTP esmalt midagi teeb ja seejärel kutsub mõne teise töötleja ServeHTTP meetodi.

Nagu eespool mainitud, genereerivad töötlejad lihtsalt päringutele vastuseid. Kuid millist konkreetset käitlejat tuleks konkreetsel ajahetkel kasutada?

Taotle marsruutimist

Õige valiku tegemiseks kasutage HTTP multiplekserit. Paljudes raamatukogudes nimetatakse seda muxeriks või ruuteriks, kuid need on kõik samad. Multiplekseri ülesanne on analüüsida päringu teed ja valida sobiv töötleja.

Kui vajate keeruka marsruutimise tuge, on parem kasutada kolmandate osapoolte teeke. Mõned kõige arenenumad - gorilla/mux и go-chi/chi, võimaldavad need teegid ilma probleemideta rakendada vahetöötlust. Nende abiga saate konfigureerida metamärgi marsruutimist ja täita mitmeid muid toiminguid. Nende eeliseks on ühilduvus standardsete HTTP-käsitlejatega. Selle tulemusena saate kirjutada lihtsa koodi, mida saab tulevikus muuta.

Tavaolukorras keerukate raamistikega töötamine nõuab mittestandardseid lahendusi ja see raskendab oluliselt vaiketöötlejate kasutamist. Enamiku rakenduste loomiseks piisab vaiketeegi ja lihtsa ruuteri kombinatsioonist.

Päringu töötlemine

Lisaks vajame komponenti, mis "kuulab" sissetulevaid ühendusi ja suunab kõik päringud õigele töötlejale. http.Server saab selle ülesandega hõlpsalt hakkama.

Alljärgnevalt on näha, et server vastutab kõigi ühenduse töötlemisega seotud ülesannete eest. See töötab näiteks TLS-protokolli kasutades. Kõne http.ListenAndServer rakendamiseks kasutatakse standardset HTTP-serverit.

Vaatame nüüd keerukamaid näiteid.

Lisan Let's Encrypt

Vaikimisi töötab meie rakendus HTTP-protokolli kaudu, kuid soovitatav on kasutada HTTPS-protokolli. Seda saab Go-s probleemideta teha. Kui olete saanud sertifikaadi ja privaatvõtme, siis piisab ListenAndServeTLS-i registreerimisest õigete sertifikaadi- ja võtmefailidega.

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

Alati saab paremini teha.

Let's Encrypt pakub tasuta sertifikaate koos automaatse uuendamisega. Teenuse kasutamiseks on vaja paketti autocert.

Lihtsaim viis selle seadistamiseks on kasutada meetodit autocert.NewListener koos funktsiooniga http.Serve. See meetod võimaldab teil hankida ja värskendada TLS-sertifikaate, kui HTTP-server töötleb päringuid:

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

Kui avame brauseris example.com, saame HTTPS-i vastuse "Tere, maailm!"

Kui vajate täpsemat seadistust, peaksite kasutama autocert.Manager manageri. Seejärel loome oma http.Serveri eksemplari (seni kasutasime seda vaikimisi) ja lisame TLSConfigi serverisse halduri:

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-i toe juurutamiseks koos automaatse sertifikaadi uuendamisega.

Kohandatud marsruutide lisamine

Standardteegi vaikeruuter on hea, kuid väga lihtne. Enamik rakendusi nõuab keerukamat marsruutimist, sealhulgas pesastatud ja metamärgiga marsruute, või teemustrite ja parameetrite määramise protseduuri.

Sel juhul tasub kasutada pakette gorilla/mux и go-chi/chi. Õpime töötama viimasega – näide on toodud allpool.

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
}

Seadsime põhifailis marsruutide jaoks api/vq prefiksi.

Seejärel saame selle paigaldada oma põhiruuterile api/v1/ prefiksi alla tagasi meie põhirakenduses:

// 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 suurte ja keerukate rakenduste struktureerimist ja hooldust.

Vahevaraga töötamine

Lavastus hõlmab ühe HTTP-käsitleja mähkimist teisega, mis võimaldab kiiresti teostada autentimist, tihendamist, logimist ja mitmeid muid funktsioone.

Vaatame näiteks http.Handleri liidest, mille abil kirjutame teenuse kasutajaid autentiva töötleja.

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

On olemas kolmanda osapoole ruuterid, näiteks chi, mis võimaldavad teil vahevara funktsionaalsust laiendada.

Staatiliste failidega töötamine

Go standardteek sisaldab staatilise sisuga töötamise võimalusi, sealhulgas pilte, JavaScripti ja CSS-faile. Neile pääseb juurde funktsiooni http.FileServer kaudu. See tagastab töötleja, mis teenindab faile kindlast kataloogist.

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

Kindlasti tasub meeles pidada, et http.Dir kuvab kataloogi sisu, kui see ei sisalda põhifaili index.html. Sel juhul peaksite kataloogi kahjustamise vältimiseks kasutama paketti unindexed.

Õige väljalülitamine

Go'l on ka funktsioon, mida nimetatakse HTTP-serveri graatsiliseks sulgemiseks. Seda saab teha kasutades Shutdown() meetodit. Server käivitatakse gorutiinis ja seejärel kuulatakse kanalit katkestussignaali vastuvõtmiseks. Niipea kui signaal vastu võetakse, lülitub 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...))
}()
 
// 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)

Kokkuvõtteks

Go on võimas keel, millel on peaaegu universaalne standardne raamatukogu. Selle vaikevõimalused on väga laiad ja neid saab liideste abil täiustada – see võimaldab arendada tõeliselt töökindlaid HTTP-servereid.

Skillbox soovitab:

Allikas: www.habr.com

Lisa kommentaar