
Před pěti lety jsem začal , což mi umožnilo se seznámit s Golangem. Uvědomil jsem si, že Go je mocný jazyk, jehož možnosti doplňují množství knihoven. Go je univerzální: zejména díky němu je možné bez problémů vyvíjet serverové aplikace.
Tento článek je věnován psaní serveru v Go. Začneme s jednoduchými věcmi, jako je „Hello world!“, a skončíme aplikací s následujícími funkcemi:
— Použití Let’s Encrypt pro HTTPS.
— Práce jako API router.
— Práce s middleware.
— Zpracování statických souborů.
— Správné ukončení aplikace.
Skillbox doporučuje: Praktický kurz .
Připomínáme: pro všechny čtenáře "Habra" – sleva 10 000 korun při registraci na jakýkoli kurz Skillbox s promokódem "Habr".
Ahoj, světe!
Vytvořit webový server v Go lze velmi rychle. Zde je příklad použití zpracovatele, který vrací slíbené „Ahoj, světe!“.
package main
import (
"fmt"
"net/http"
)
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Ahoj světe!")
})
http.ListenAndServe(":80", nil)
}Poté, co aplikaci spustíte a otevřete stránku , uvidíte okamžitě text „Ahoj, světe!“ (samozřejmě, pokud všechno funguje správně).
Dále budeme opakovaně používat zpracovatele, ale nejprve si pojďme objasnit, jak všechno funguje.
net/http
V příkladu byl použit balíček , což je hlavní nástroj v Go pro vývoj jak serverů, tak HTTP klientů. Abychom porozuměli kódu, pojďme si vysvětlit význam tří důležitých prvků: http.Handler, http.ServeMux a http.Server.
HTTP zpracovatelé
Když obdržíme požadavek, zpracovatel jej analyzuje a vytvoří odpověď. Zpracovatelé v Go jsou implementováni následujícím způsobem:
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}V prvním příkladu se používá pomocná funkce http.HandleFunc. Ta obaluje jinou funkci, která naopak přijímá http.ResponseWriter a http.Request v ServeHTTP.
Jinými slovy, zpracovatelé v Golangu jsou prezentovány jednotným rozhraním, což programátorovi poskytuje mnoho možností. Například middleware je realizováno pomocí zpracovatele, kde ServeHTTP nejprve něco udělá a poté zavolá metodu ServeHTTP jiného zpracovatele.
Jak bylo uvedeno výše, zpracovatelé jednoduše vytvářejí odpovědi na požadavky. Ale který konkrétní zpracovatel by měl být použit v daném okamžiku?
Směrování požadavků
Aby učinili správnou volbu, využijte HTTP multiplexor. V některých knihovnách se mu říká muxer nebo router, ale všechny tyto termíny označují totéž. Funkce multiplexoru spočívá v analýze cesty požadavku a výběru odpovídajícího zpracovatele.
Pokud potřebujete podporu složitého směrování, je lepší využít specializované knihovny. Některé z nejpokročilejších jsou a , tyto knihovny umožňují implementaci mezisouborového zpracování bez větších problémů. Díky nim lze nastavit wildcard směrování a provést další úkoly. Jejich výhodou je kompatibilita se standardními HTTP zpracovateli. Výsledkem je, že můžete napsat jednoduchý kód s možností jeho budoucí modifikace.
Práce se složitými frameworky v běžné situaci vyžaduje nestandardní řešení, což značně ztěžuje použití výchozích zpracovatelů. Pro většinu aplikací postačí kombinace výchozí knihovny a jednoduchého routeru.
Zpracování požadavků
Dále potřebujeme komponent, který bude 'poslouchat' příchozí spojení a směrovat všechny požadavky správnému zpracovateli. Tento úkol snadno zvládne http.Server.
Níže je uvedeno, že server odpovídá za všechny úkoly, které se týkají zpracování spojení. To zahrnuje například práci s protokolem TLS. Pro realizaci volání http.ListenAndServer se používá standardní HTTP server.
Nyní se podívejme na složitější příklady.
Přidání Let’s Encrypt
Ve výchozím nastavení naše aplikace funguje na HTTP protokolu, avšak doporučuje se používat HTTPS protokol. V Go to lze snadno provést. Pokud jste obdrželi certifikát a soukromý klíč, stačí napsat ListenAndServeTLS s uvedením správných souborů certifikátu a klíče.
http.ListenAndServeTLS(":443", "cert.pem", "key.pem", nil)Vždy je možné udělat to lépe.
nabízí bezplatné certifikáty s možností automatické obnovy. K využití této služby je potřeba balíček autocert.
Nejjednodušší způsob, jak ho nastavit, je použít metodu autocert.NewListener v kombinaci s http.Serve. Tato metoda umožňuje získávat a obnovovat TLS certifikáty, zatímco HTTP server zpracovává požadavky:
http.Serve(autocert.NewListener("example.com"), nil)Pokud to otevřeme v prohlížeči , dostaneme HTTPS-odpověď „Hello, world!“.
Pokud potřebujete podrobnější nastavení, je dobré použít správce autocert.Manager. Poté vytvoříme vlastní instanci http.Server (dosud jsme používali výchozí) a přidáme správce do serveru 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("", "")To je jednoduchý způsob, jak implementovat plnou podporu HTTPS s automatickou obnovou certifikátu.
Přidání nestandardních tras
Výchozí směrovač, který je součástí standardní knihovny, je dobrý, ale velmi jednoduchý. Většina aplikací potřebuje složitější směrování, včetně vnořených a wildcard tras nebo procedury pro nastavování šablon a parametrů cest.
V tomto případě stojí za to použít balíčky a . S tím posledním se naučíme pracovat — níže je uveden příklad.
Dáno — soubor api/v1/api.go, který obsahuje trasy pro naše 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
}Nastavíme pro trasy prefix api/vq v hlavním souboru.
Pak to můžeme připojit k našemu hlavnímu směrovači pod prefixem api/v1 zpět v naší hlavní aplikaci:
// 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())Jednoduchost práce se složitými trasami v Go umožňuje zjednodušit strukturování s údržbou velkých komplexních aplikací.
Práce s middlewarem
Při zpracování prostřednictvím middleware se používá obalování jednoho HTTP zpracovatele jiným, což umožňuje rychlé provádění ověřování, komprese, protokolování a některých dalších funkcí.
Jako příklad si vezmeme rozhraní http.Handler, s jehož pomocí napíšeme zpracovatele s ověřováním uživatelů služby.
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
}
// Předpokládáme, že ověření prošlo, spusťte původní zpracovatele
next.ServeHTTP(w, r)
})
}Existují externí směrovače, například chi, které umožňují rozšířit funkčnost middleware.
Práce se statickými soubory
Standardní knihovna Go obsahuje možnosti pro práci se statickým obsahem, včetně obrázků a souborů JavaScript a CSS. Přístup k nim je možné získat prostřednictvím funkce http.FileServer. Ta vrací zpracovatele, který distribuuje soubory z určeného adresáře.
func NewRouter() http.Handler {
router := chi.NewRouter()
r.Get("/{name}", HelloName)
// Nastavení statického souboru
staticPath, _ := filepath.Abs("../../static/")
fs := http.FileServer(http.Dir(staticPath))
router.Handle("/*", fs)
return rJe důležité si pamatovat, že http.Dir zobrazuje obsah adresáře pouze v případě, že neobsahuje hlavní soubor index.html. V tomto případě, abychom zabránili kompromitaci adresáře, je dobré použít balíček .
Správné ukončení práce
V Go existuje funkce pro správné ukončení HTTP serveru. To lze provést pomocí metody Shutdown(). Server běží v gorutině a následně se naslouchá kanálu pro příjem signálu přerušení. Jakmile je signál přijat, server se nezačne okamžitě vypínat, ale až po několika sekundách.
handler := server.NewRouter()
srv := &http.Server{
Handler: handler,
}
go func() {
srv.Serve(autocert.NewListener(domains...))
}()
// Čekání na přerušení
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt)
<-c
// Pokus o správné ukončení
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
srv.Shutdown(ctx)Na závěr
Go je mocný jazyk s prakticky univerzální standardní knihovnou. Jeho výchozí vlastnosti jsou velmi široké, a ty lze posílit pomocí rozhraní — což umožňuje skutečně spolehlivý vývoj HTTP serverů.
Skillbox doporučuje:
- Dvouroční praktický kurz .
- Vzdělávací online kurz .
- Praktický roční kurz .
Zdroj: habr.com
