Żvilupp ta 'web server f'Golang - minn sempliċi għal kumpless

Żvilupp ta 'web server f'Golang - minn sempliċi għal kumpless

Ħames snin ilu bdejt tiżviluppa Gophish, dan ipprovda opportunità biex titgħallem Golang. Irrealizzajt li Go hija lingwa qawwija, ikkumplimentata minn ħafna libreriji. Go hija versatili: b'mod partikolari, tista 'tintuża biex tiżviluppa applikazzjonijiet fuq in-naħa tas-server mingħajr problemi.

Dan l-artikolu huwa dwar il-kitba ta 'server f'Go. Nibdew b'affarijiet sempliċi bħal "Hello world!" u nispiċċaw b'applikazzjoni bil-kapaċitajiet li ġejjin:

- Uża Let's Encrypt għal HTTPS.
— Jaħdem bħala router API.
— Ħidma mal-middleware.
— Ipproċessar ta' fajls statiċi.
— Tfiq korrett.

Skillbox jirrakkomanda: Kors prattiku "Żviluppatur Python mill-bidu".

Infakkrukom: għall-qarrejja kollha ta '"Habr" - skont ta' 10 rublu meta tirreġistra fi kwalunkwe kors ta 'Skillbox billi tuża l-kodiċi promozzjonali "Habr".

Hello dinja!

Tista 'toħloq web server f'Go malajr ħafna. Hawn eżempju ta 'użu ta' handler li jirritorna l-"Hello, world!" mwiegħed hawn fuq.

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

Wara dan, jekk tmexxi l-applikazzjoni u tiftaħ il-paġna localhost, imbagħad immedjatament tara t-test "Hello, dinja!" (jekk kollox jaħdem sew, ovvjament).

Ser nużaw il-handler diversi drabi aktar tard, imma l-ewwel ejja nifhmu kif jaħdem kollox.

net/http

L-eżempju uża l-pakkett net/http, hija l-għodda primarja f'Go għall-iżvilupp kemm ta' servers kif ukoll ta' klijenti HTTP. Biex tifhem il-kodiċi, ejja nifhmu t-tifsira ta 'tliet elementi importanti: http.Handler, http.ServeMux u http.Server.

HTTP handlers

Meta nirċievu talba, il-handler janalizzaha u jiġġenera tweġiba. Handlers f'Go huma implimentati kif ġej:

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

L-ewwel eżempju juża l-funzjoni helper http.HandleFunc. Hija wraps funzjoni oħra, li mbagħad tieħu http.ResponseWriter u http.Request fis ServeHTTP.

Fi kliem ieħor, handlers f'Golang huma ppreżentati f'interface waħda, li tagħti ħafna għażliet lill-programmatur. Allura, pereżempju, middleware huwa implimentat bl-użu ta 'handler, fejn ServeHTTP l-ewwel jagħmel xi ħaġa u mbagħad isejjaħ il-metodu ServeHTTP ta' handler ieħor.

Kif imsemmi hawn fuq, handlers sempliċement jiġġeneraw tweġibiet għat-talbiet. Imma liema handler partikolari għandu jintuża f'punt partikolari fil-ħin?

Itlob Rotot

Biex tagħmel l-għażla t-tajba, uża multiplexer HTTP. F'numru ta 'libreriji huwa msejjaħ muxer jew router, iżda huma kollha l-istess ħaġa. Il-funzjoni tal-multiplexer hija li tanalizza l-mogħdija tat-talba u tagħżel l-immaniġġjar xieraq.

Jekk għandek bżonn appoġġ għal rotta kumplessa, allura huwa aħjar li tuża libreriji ta 'partijiet terzi. Uħud mill-aktar avvanzati - gorilla/mux и go-chi/chi, dawn il-libreriji jagħmluha possibbli li jiġi implimentat ipproċessar intermedju mingħajr problemi. Bl-għajnuna tagħhom, tista 'tikkonfigura r-routing wildcard u twettaq numru ta' kompiti oħra. Il-vantaġġ tagħhom huwa l-kompatibilità ma 'handlers HTTP standard. Bħala riżultat, tista 'tikteb kodiċi sempliċi li jista' jiġi modifikat fil-futur.

Il-ħidma ma' oqfsa kumplessi f'sitwazzjoni normali se teħtieġ soluzzjonijiet mhux standard, u dan jikkomplika b'mod sinifikanti l-użu ta 'handlers default. Biex tinħoloq il-maġġoranza l-kbira tal-applikazzjonijiet, taħlita tal-librerija default u router sempliċi tkun biżżejjed.

Ipproċessar tal-Mistoqsija

Barra minn hekk, neħtieġu komponent li "jisma" għall-konnessjonijiet deħlin u jidderieġi mill-ġdid it-talbiet kollha lill-handler korrett. http.Server jista 'faċilment jimmaniġġja dan il-kompitu.

Dan li ġej juri li s-server huwa responsabbli għall-kompiti kollha li huma relatati mal-ipproċessar tal-konnessjoni. Dan, pereżempju, jaħdem bl-użu tal-protokoll TLS. Biex timplimenta s-sejħa http.ListenAndServer, jintuża server HTTP standard.

Issa ejja nħarsu lejn eżempji aktar kumplessi.

Żieda Let's Encrypt

B'mod awtomatiku, l-applikazzjoni tagħna taħdem fuq il-protokoll HTTP, iżda huwa rakkomandat li tuża l-protokoll HTTPS. Dan jista' jsir mingħajr problemi f'Go. Jekk irċevejt ċertifikat u ċavetta privata, allura huwa biżżejjed li tirreġistra ListenAndServeTLS maċ-ċertifikat korrett u l-fajls taċ-ċavetta.

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

Dejjem tista’ tagħmel aħjar.

Let's Encrypt jipprovdi ċertifikati b'xejn b'tiġdid awtomatiku. Sabiex tuża s-servizz, għandek bżonn pakkett autocert.

L-eħfef mod biex jiġi kkonfigurat huwa li tuża l-metodu autocert.NewListener flimkien ma 'http.Serve. Il-metodu jippermettilek tikseb u taġġorna ċertifikati TLS waqt li s-server HTTP jipproċessa talbiet:

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

Jekk niftħu fil-browser example.com, se nirċievu tweġiba HTTPS "Hello, world!"

Jekk għandek bżonn konfigurazzjoni aktar dettaljata, allura għandek tuża l-maniġer autocert.Manager. Imbagħad noħolqu l-istanza http.Server tagħna stess (sa issa użajna b'mod awtomatiku) u żid il-maniġer mas-server TLSConfig:

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

Dan huwa mod faċli biex jiġi implimentat appoġġ HTTPS sħiħ bit-tiġdid awtomatiku taċ-ċertifikat.

Żieda ta 'rotot tad-dwana

Ir-router default inkluż fil-librerija standard huwa tajjeb, iżda huwa bażiku ħafna. Ħafna applikazzjonijiet jeħtieġu rotta aktar kumplessa, inklużi rotot nested u wildcard, jew proċedura għall-iffissar tal-mudelli u l-parametri tal-mogħdijiet.

F'dan il-każ ta 'min juża pakketti gorilla/mux и go-chi/chi. Aħna se nitgħallmu naħdmu ma 'dawn tal-aħħar - eżempju jidher hawn taħt.

Mogħti l-fajl api/v1/api.go li fih ir-rotot għall-API tagħna:

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

Aħna nissettjaw il-prefiss api/vq għar-rotot fil-fajl prinċipali.

Imbagħad nistgħu narmaw dan mar-router prinċipali tagħna taħt il-prefiss api/v1/ lura fl-applikazzjoni ewlenija tagħna:

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

Il-faċilità ta' Go biex taħdem b'rotot kumplessi tagħmilha possibbli li tissimplifika l-istrutturar u l-manutenzjoni ta' applikazzjonijiet kbar u kumplessi.

Ħidma ma middleware

L-istadju jinvolvi t-tgeżwir ta 'handler HTTP wieħed ma' ieħor, li jagħmilha possibbli li jitwettqu malajr awtentikazzjoni, kompressjoni, illoggjar, u bosta funzjonijiet oħra.

Bħala eżempju, ejja nħarsu lejn l-interface http.Handler; aħna ser nużawha biex niktbu handler li jawtentika l-utenti tas-servizz.

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

Hemm routers ta 'partijiet terzi, bħal chi, li jippermettulek testendi l-funzjonalità tal-middleware.

Ħidma ma 'fajls statiċi

Il-librerija standard Go tinkludi kapaċitajiet biex taħdem b'kontenut statiku, inklużi stampi, JavaScript u fajls CSS. Jistgħu jiġu aċċessati permezz tal-funzjoni http.FileServer. Jirritorna handler li jservi fajls minn direttorju speċifiku.

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

Żgur ta’ min jiftakar li http.Dir juri l-kontenut tad-direttorju jekk ma jkunx fih il-fajl index.html prinċipali. F'dan il-każ, biex tevita li d-direttorju jiġi kompromess, għandek tuża l-pakkett unindexed.

Tfiq korrett

Go għandu wkoll karatteristika msejħa għeluq graceful tas-server HTTP. Dan jista' jsir bl-użu tal-metodu Shutdown(). Is-server jinbeda f'goroutine, u mbagħad il-kanal jinstema' biex jirċievi sinjal ta 'interruzzjoni. Hekk kif is-sinjal jiġi riċevut, is-server jintefa, iżda mhux immedjatament, iżda wara ftit sekondi.

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)

Bħala konklużjoni

Go hija lingwa qawwija b'librerija standard kważi universali. Il-kapaċitajiet default tagħha huma wesgħin ħafna, u jistgħu jittejbu bl-użu ta' interfaces - dan jippermettilek tiżviluppa servers HTTP tassew affidabbli.

Skillbox jirrakkomanda:

Sors: www.habr.com

Żid kumment