
För fem Är sedan började jag , vilket gav mig möjlighet att lÀra mig Golang. Jag insÄg att Go Àr ett kraftfullt sprÄk vars möjligheter kompletteras av mÄnga bibliotek. Go Àr mÄngsidigt: framför allt kan man utan problem utveckla serverapplikationer med det.
Denna artikel handlar om att skriva en server i Go. Vi börjar med enkla saker, som "Hello world!", och avslutar med en applikation med följande funktioner:
â AnvĂ€ndning av Let's Encrypt för HTTPS.
â Arbetar som en API-ruttare.
â Arbetar med middleware.
â Hantering av statiska filer.
â Korrekt avslutande av arbetet.
Skillbox rekommenderar: Praktisk kurs .
PĂ„minnelse: för alla lĂ€sare av "Habr" â 10 000 rubel rabatt vid registrering för vilken kurs som helst pĂ„ Skillbox med rabattkoden "Habr".
Hej, vÀrlden!
Att skapa en webbserver i Go gÄr mycket snabbt. HÀr Àr ett exempel pÄ en hanterare som returnerar den ovan nÀmnda "Hello, world!".
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)
}Efter detta, om du startar applikationen och öppnar sidan , kommer du omedelbart att se texten "Hello, world!" (naturligtvis om allt fungerar som det ska).
DÀrefter kommer vi att anvÀnda hanteraren flera gÄnger, men först lÄt oss förstÄ hur allt fungerar.
net/http
I exemplet anvÀndes paketet , det Àr huvudsakligt verktyg i Go för att utveckla bÄde servrar och HTTP-klienter. För att förstÄ koden, lÄt oss gÄ igenom betydelsen av tre viktiga element: http.Handler, http.ServeMux och http.Server.
HTTP-hanterare
NÀr vi fÄr en begÀran analyserar hanteraren den och formar ett svar. Hanterarna i Go implementeras pÄ följande sÀtt:
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}I det första exemplet anvÀnds hjÀlpfunktionen http.HandleFunc. Den omsluter en annan funktion som i sin tur tar http.ResponseWriter och http.Request i ServeHTTP.
Med andra ord, hanterarna i Golang representeras av ett enda grÀnssnitt, vilket ger mÄnga möjligheter för programmeraren. Till exempel, middleware implementeras med hjÀlp av en hanterare, dÀr ServeHTTP först gör nÄgot och sedan anropar ServeHTTP-metoden för en annan hanterare.
Som tidigare nÀmnts formar hanterarna helt enkelt svar pÄ begÀrningar. Men vilken specifik hanterare ska man anvÀnda vid ett givet tillfÀlle?
Ruttning av begÀrningar
För att göra ett korrekt val, anvÀnd HTTP-multiplexern. I flera bibliotek kallas den muxer eller router, men allt detta Àr samma sak. Multiplexerns funktion Àr att analysera sökvÀgen för förfrÄgan och vÀlja motsvarande hanterare.
Om du behöver stöd för mer komplexa ruttningar, Àr det bÀttre att anvÀnda externa bibliotek. NÄgra av de mest avancerade Àr och , dessa bibliotek möjliggör mellanliggande bearbetning utan större problem. Med deras hjÀlp kan du konfigurera wildcard-routing och utföra en rad andra uppgifter. Deras fördel Àr kompatibilitet med standard HTTP-hanterare. Som ett resultat kan du skriva enkel kod med möjlighet till framtida modifieringar.
Arbete med komplexa ramverk i vanliga situationer krÀver inte helt standardlösningar, vilket vÀsentligt komplicerar anvÀndningen av standardhanterare. För att skapa majoriteten av applikationerna rÀcker det med en kombination av det standardbiblioteket och en enkel router.
BegÀrningshantering
Dessutom behöver vi en komponent som 'lyssnar' pÄ inkommande anslutningar och dirigerar alla förfrÄgningar till rÀtt hanterare. Denna uppgift klarar http.Server utan problem.
Nedan visas att servern ansvarar för alla uppgifter relaterade till behandlingen av anslutningar. Det handlar till exempel om arbete enligt TLS-protokollet. För att implementera anropet http.ListenAndServer anvÀnds standard HTTP-servern.
Nu ska vi titta pÄ mer komplexa exempel.
TillĂ€gg av Letâs Encrypt
Som standard fungerar vÄr applikation via HTTP-protokollet, men det rekommenderas att anvÀnda HTTPS-protokollet. I Go gÄr detta utan problem. Om du har fÄtt ett certifikat och en privat nyckel, rÀcker det med att ange ListenAndServeTLS med rÀtt filer för certifikatet och nyckeln.
http.ListenAndServeTLS(":443", "cert.pem", "key.pem", nil)Det gÄr alltid att göra det bÀttre.
erbjuder gratis certifikat med möjlighet till automatisk förnyelse. För att anvÀnda tjÀnsten behövs paketet autocert.
Det enklaste sÀttet att konfigurera det Àr att anvÀnda metoden autocert.NewListener i kombination med http.Serve. Metoden gör det möjligt att fÄ och förnya TLS-certifikat, medan HTTP-servern hanterar förfrÄgningarna:
http.Serve(autocert.NewListener("example.com"), nil)Om vi öppnar i webblÀsaren , fÄr vi HTTPS-svar "Hello, world!".
Om du behöver en mer noggrann konfiguration, bör du anvÀnda autocert.Manager. Skapa sedan din egen instans av http.Server (hittills har vi anvÀnt standardinstansen) och lÀgg till managern i serverns 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("", "")Detta Àr ett enkelt sÀtt att implementera fullstÀndigt stöd för HTTPS med automatisk certifikatförnyelse.
LĂ€gga till icke-standardrutter
Den standardrouter som ingÄr i standardbiblioteket Àr bra, men den Àr mycket enkel. De flesta applikationer behöver en mer komplicerad routing, inklusive inbÀddade och wildcard-rutter eller en process för att stÀlla in mallar och vÀgparameterar.
I det hĂ€r fallet bör vi anvĂ€nda paketen och . Vi kommer att lĂ€ra oss att arbeta med det â en exempel visas nedan.
Givet â filen api/v1/api.go, som innehĂ„ller rutter för vĂ„rt 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
}Vi sÀtter en prefix för rutter api/vq i huvudfilen.
Vi kan sedan montera detta pÄ vÄr huvudrouter under prefixet api/v1 i vÄr huvudapplikation:
// 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())Enkelheten i att arbeta med komplexa rutter i Go gör det möjligt att förenkla strukturen för att hantera stora och komplexa applikationer.
Arbeta med mellanprogram
Vid anvÀndning av mellanprogram omger man en HTTP-behandlare med en annan, vilket möjliggör snabb autentisering, komprimering, loggning och nÄgra andra funktioner.
Som exempel, lÄt oss titta pÄ grÀnssnittet http.Handler, med hjÀlp av detta skriver vi en behandlare med autentisering för anvÀndare av tjÀnsten.
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
}
// Om autentiseringen lyckades, kör den ursprungliga behandlaren
next.ServeHTTP(w, r)
})
}Det finns externa routrar som chi, som möjliggör utökning av funktionaliteten för mellanprogram.
Arbeta med statiska filer
Standardbiblioteket i Go inkluderar funktioner för att hantera statiskt innehÄll, inklusive bilder, samt JavaScript- och CSS-filer. à tkomst till dem kan göras via funktionen http.FileServer. Den returnerar en behandlare som serverar filer frÄn en specifik katalog.
func NewRouter() http.Handler {
router := chi.NewRouter()
r.Get("/{name}", HelloName)
// Konfigurera distribution av statiska filer
staticPath, _ := filepath.Abs("../..//static/")
fs := http.FileServer(http.Dir(staticPath))
router.Handle("/*", fs)
return rDet Àr viktigt att komma ihÄg att http.Dir visar innehÄllet i katalogen om det inte finns nÄgon huvudfil index.html i den. I detta fall, för att undvika katalogkompromiss, bör paketet anvÀndas .
Korrekt avstÀngning
I Go finns det ocksÄ en funktion för korrekt avstÀngning av HTTP-servern. Detta kan göras med hjÀlp av metoden Shutdown(). Servern startas i en goroutine, och sedan lyssnas pÄ kanalen för att ta emot avbrottssignaler. SÄ snart signalen tas emot stÀngs servern ner, men inte omedelbart, utan efter nÄgra sekunder.
handler := server.NewRouter()
srv := &http.Server{
Handler: handler,
}
go func() {
srv.Serve(autocert.NewListener(domains...))
}()
// VÀnta pÄ ett avbrott
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt)
<-c
// Försök en smidig avstÀngning
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
srv.Shutdown(ctx)Som en avslutning
Go Ă€r ett kraftfullt sprĂ„k med en praktiskt taget universell standardbibliotek. Dess standardfunktioner Ă€r ganska omfattande, och de kan förstĂ€rkas med hjĂ€lp av grĂ€nssnitt â detta möjliggör utveckling av verkligt tillförlitliga HTTP-servrar.
Skillbox rekommenderar:
- TvÄÄrig praktisk kurs .
- Utbildningskurs online .
- Praktisk Ärskurs .
KĂ€lla: habr.com
