Sviluppà servitori web in Golang - da simplice à cumplessu
Cinque anni fà aghju cuminciatu sviluppà Gophish, hà permessu di amparà Golang. Aghju realizatu chì Go hè una lingua putente, chì hè cumplementata da parechje biblioteche. Go hè versatile: in particulare, pudete facilmente sviluppà applicazioni di u servitore cun ellu.
Questu articulu hè di scrive un servitore in Go. Cuminciamu cù cose simplici cum'è "Hello world!" è finiscinu cù una applicazione cù queste caratteristiche:
- Utilizendu Let's Encrypt per HTTPS.
- U travagliu cum'è un router API.
- U travagliu cù middleware.
- Gestione di fugliali statichi.
- Arregu currettu.
Dopu à quessa, si eseguite l'applicazione è apre a pagina localhost, tandu vi vede subitu u testu "Hello, world!" (di sicuru, se tuttu funziona bè).
Adupremu u gestore ripetutamente in u seguitu, ma prima capemu cumu tuttu funziona.
net/http
L'esempiu hà utilizatu u pacchettu net/http, hè u strumentu primariu di Go per sviluppà i servitori è i clienti HTTP. Per capisce u codice, capiscenu u significatu di trè elementi impurtanti: http.Handler, http.ServeMux è http.Server.
I gestori HTTP
Quandu ricevemu una dumanda, u gestore l'analiza è genera una risposta. I gestori in Go sò implementati cusì:
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
U primu esempiu usa a funzione http.HandleFunc helper. Imballa una altra funzione chì in turnu accetta http.ResponseWriter è http.Request in ServeHTTP.
In altri palori, i gestori in Golang sò rapprisentati da una sola interfaccia, chì dà assai opportunità per u programatore. Cusì, per esempiu, u middleware hè implementatu cù un gestore, induve ServeHTTP prima face qualcosa è poi chjama u metudu ServeHTTP di un altru gestore.
Cum'è l'esitatu sopra, i gestori solu formanu risposte à e dumande. Ma quale gestore deve esse usatu in un mumentu particulare?
Richiesta di routing
Per fà a scelta bona, utilizate u multiplexer HTTP. In una quantità di biblioteche hè chjamatu muxer o router, ma sò tutti listessi. A funzione di u multiplexer hè di analizà a strada di a dumanda è selezziunate u gestore adattatu.
Sè avete bisognu di supportu per u routing cumplessu, allora hè megliu aduprà biblioteche di terzu. Unu di i più avanzati gorilla/mux и go-chi/chi, sti biblioteche facenu pussibile implementà u prucessu intermediu senza prublemi. Cù u so aiutu, pudete stabilisce u routing wildcard è eseguisce una quantità di altre attività. U so vantaghju hè a cumpatibilità cù i manipulatori HTTP standard. In u risultatu, pudete scrive un codice simplice chì pò esse mudificatu in u futuru.
U travagliu cù frameworks cumplessi in una situazione normale richiederà suluzioni micca abbastanza standard, è questu complica assai l'usu di i gestori predeterminati. A cumminazzioni di a biblioteca predeterminata è un router simplice serà abbastanza per creà a maiò parte di l'applicazioni.
Trattamentu di e dumande
Inoltre, avemu bisognu di un cumpunente chì "ascolta" per e cunnessione entranti è redirige tutte e dumande à u gestore currettu. http.Server pò facilmente affruntà stu compitu.
I seguenti mostra chì u servitore hè rispunsevule per tutti i travaglii ligati à a gestione di e cunnessione. Questu hè, per esempiu, u travagliu nantu à u protocolu TLS. Un servitore HTTP standard hè utilizatu per implementà a chjama http.ListenAndServer.
Avà fighjemu esempi più cumplessi.
Aghjunghjendu Let's Encrypt
Per automaticamente, a nostra applicazione corre nantu à u protocolu HTTP, ma hè cunsigliatu di utilizà u protocolu HTTPS. In Go, questu pò esse fattu senza prublemi. Sè avete ricevutu un certificatu è una chjave privata, allora hè abbastanza per scrive ListenAndServeTLS cù u certificatu currettu è i schedarii chjave.
Let's Crypt dà certificati gratuiti cù a pussibilità di rinnuvamentu automaticu. Per utilizà u serviziu, avete bisognu di un pacchettu autocert.
A manera più faciule di stallà hè di utilizà u metudu autocert.NewListener in cumminazione cù http.Serve. U metudu permette di riceve è rinnuvà i certificati TLS mentre u servitore HTTP processa e dumande:
Sè avemu apertu in u navigatore example.com, avemu una risposta HTTPS "Hello, world!".
Sè avete bisognu di cunfigurazione più dettagliata, allora avete aduprà l'autocert.Manager. Allora creamu u nostru propiu http.Server instance (finu à avà l'avemu utilizatu per difettu) è aghjunghje u manager à u servitore TLSConfig:
Questu hè un modu faciule per implementà un supportu HTTPS cumpletu cù rinnuvamentu automaticu di certificati.
Aghjunghjendu Routes Custom
U router predeterminatu inclusu in a biblioteca standard hè bellu, ma assai basicu. A maiò parte di l'applicazioni necessitanu un routing più cumplessu, cumprese rotte nidificate è wildcard, o a prucedura per stabilisce mudelli di percorsi è paràmetri.
In questu casu, avete aduprà pacchetti gorilla/mux и go-chi/chi. Avemu da amparà cumu travaglià cù l'ultime - un esempiu hè mostratu quì sottu.
Hè datu u schedariu api/v1/api.go chì cuntene e rotte per a nostra API:
/ 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
}
Avemu stabilitu u prefissu api/vq per e rotte in u schedariu principale.
Pudemu allora muntà questu à u nostru router principale sottu u prefissu api/v1/ in a nostra applicazione principale:
// 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())
A facilità di travaglià cù rotte cumplessi in Go permette di simplificà a strutturazione è u mantenimentu di grandi applicazioni cumplessi.
U travagliu cù middleware
In u casu di u prucessu intermediu, l'imbulighjate un handler HTTP cù un altru hè utilizatu, chì permette di realizà rapidamente l'autentificazione, a compressione, u logging è alcune altre funzioni.
Per esempiu, cunsideremu l'interfaccia http.Handler, cù u so aiutu scriveremu un handler cù l'autentificazione di l'utilizatori di serviziu.
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)
})
}
Ci sò routers di terzu partitu, cum'è chi, chì permettenu di allargà a funziunalità di u prucessu intermediariu.
U travagliu cù i schedari statici
A biblioteca standard di Go include facilità per travaglià cù cuntenutu staticu, cumprese l'imaghjini, è ancu i schedari JavaScript è CSS. Si ponu accede à traversu a funzione http.FileServer. Ritorna un gestore chì distribuisce i schedari da un cartulare specificu.
Assicuratevi di ricurdà chì http.Dir mostra u cuntenutu di u cartulare s'ellu ùn cuntene micca u schedariu principale index.html. In questu casu, per prevene u repertoriu da esse cumprumessi, duvete aduprà u pacchettu unindexed.
Arregu currettu
Go hà ancu una tale funzione cum'è un chjusu graziosu di u servitore HTTP. Questu pò esse fattu cù u metudu Shutdown (). U servitore hè cuminciatu in una goroutine, è dopu u canali hè intesu per riceve un signalu di interruzzione. Appena u signale hè ricivutu, u servitore si spegne, ma micca subitu, ma dopu à pocu seconde.
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)
Cum'è cunclusione
Go hè una lingua putente cù una biblioteca standard quasi universale. E so capacità predeterminate sò assai largu, è pudete rinfurzà cù l'aiutu di l'interfacce - questu permette di sviluppà servitori HTTP veramente affidabili.