Devlopman sèvè entènèt nan Golang - soti nan senp rive konplèks

Devlopman sèvè entènèt nan Golang - soti nan senp rive konplèks

Senk ane de sa mwen te kòmanse devlope Gophish, sa te bay yon opòtinite pou aprann Golang. Mwen reyalize ke Go se yon lang pwisan, konplete pa anpil bibliyotèk. Go se versatile: an patikilye, li ka itilize yo devlope aplikasyon sèvè-bò san okenn pwoblèm.

Atik sa a se sou ekri yon sèvè nan Go. Ann kòmanse ak bagay senp tankou "Bonjou mond!" epi fini ak yon aplikasyon ki gen kapasite sa yo:

- Sèvi ak Let's Encrypt pou HTTPS.
— Travay kòm yon routeur API.
— Travay ak middleware.
— Pwosesis dosye estatik.
- Fèmen kòrèk.

Skillbox rekòmande: Kou pratik "Python devlopè nan grafouyen".

Nou raple: pou tout lektè "Habr" - yon rabè nan 10 rubles lè w ap enskri nan nenpòt kou Skillbox lè l sèvi avèk kòd pwomosyon "Habr".

Bonjou, mond!

Ou ka kreye yon sèvè entènèt nan Go trè vit. Men yon egzanp lè w sèvi ak yon moun k ap okipe w ki retounen “Bonjou, monn!” yo te pwomèt pi wo a.

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

Apre sa, si ou kouri aplikasyon an epi louvri paj la lokalost, Lè sa a, ou pral imedyatman wè tèks la "Bonjou, lemonn!" (si tout bagay travay kòrèkteman, nan kou).

Nou pral sèvi ak moun kap okipe a plizyè fwa pita, men anvan ann konprann ki jan tout bagay ap fonksyone.

net/http

Egzanp lan te itilize pakè a net/http, li se zouti prensipal nan Go pou devlope tou de sèvè ak kliyan HTTP. Pou konprann kòd la, ann konprann siyifikasyon twa eleman enpòtan: http.Handler, http.ServeMux ak http.Server.

Responsab HTTP

Lè nou resevwa yon demann, moun k ap okipe a analize li epi li jenere yon repons. Handlers in Go yo aplike jan sa a:

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

Premye egzanp lan sèvi ak fonksyon asistan http.HandleFunc. Li vlope yon lòt fonksyon, ki an vire pran http.ResponseWriter ak http.Request nan ServeHTTP.

Nan lòt mo, moun kap okipe Golang yo prezante nan yon sèl koòdone, ki bay yon anpil nan opsyon pwogramè a. Se konsa, pou egzanp, middleware aplike lè l sèvi avèk yon moun k ap okipe, kote ServeHTTP premye fè yon bagay ak Lè sa a, rele metòd la ServeHTTP nan yon lòt moun k ap okipe.

Kòm mansyone pi wo a, moun kap okipe yo tou senpleman jenere repons a demann. Men, ki moun k ap okipe an patikilye yo ta dwe itilize nan yon pwen an patikilye nan tan?

Mande routage

Pou fè bon chwa, sèvi ak yon multiplexer HTTP. Nan yon kantite bibliyotèk yo rele li muxer oswa routeur, men yo tout se menm bagay la. Fonksyon multiplexer la se analize chemen demann lan epi chwazi moun kap okipe a apwopriye.

Si ou bezwen sipò pou routage konplèks, li pi bon pou itilize bibliyotèk twazyèm pati. Gen kèk nan pi avanse yo - goril/mux и go-chi/chi, bibliyotèk sa yo fè li posib pou aplike pwosesis entèmedyè san okenn pwoblèm. Avèk èd yo, ou ka configured routage wildcard epi fè yon kantite lòt travay. Avantaj yo se konpatibilite ak moun kap okipe HTTP estanda. Kòm yon rezilta, ou ka ekri kòd senp ki ka modifye nan tan kap vini an.

Travay ak kad konplèks nan yon sitiyasyon nòmal pral mande pou solisyon ki pa estanda, e sa a siyifikativman konplike itilizasyon moun k ap okipe default. Pou kreye a vas majorite de aplikasyon yo, yon konbinezon de bibliyotèk la default ak yon routeur senp pral ase.

Pwosesis rechèch

Anplis de sa, nou bezwen yon eleman ki pral "koute" pou koneksyon fèk ap rantre epi redireksyon tout demann yo bay moun k ap okipe a kòrèk. http.Server ka fasilman okipe travay sa a.

Sa ki anba la a montre ke sèvè a responsab pou tout travay ki gen rapò ak pwosesis koneksyon. Sa a, pou egzanp, travay lè l sèvi avèk pwotokòl TLS la. Pou aplike apèl http.ListenAndServer, yo itilize yon sèvè HTTP estanda.

Koulye a, ann gade nan egzanp ki pi konplèks.

Ajoute ann ankripte

Pa default, aplikasyon nou an kouri sou pwotokòl HTTP a, men li rekòmande pou itilize pwotokòl HTTPS la. Sa a ka fè san pwoblèm nan Go. Si ou te resevwa yon sètifika ak kle prive, Lè sa a, li ase yo anrejistre ListenAndServeTLS ak sètifika ki kòrèk la ak dosye kle yo.

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

Ou ka toujou fè pi byen.

Se pou yo ankripte bay sètifika gratis ak renouvèlman otomatik. Pou itilize sèvis la, ou bezwen yon pake autocert.

Fason ki pi fasil pou konfigirasyon li se sèvi ak metòd autocert.NewListener an konbinezon ak http.Serve. Metòd la pèmèt ou jwenn ak mete ajou sètifika TLS pandan sèvè HTTP a ap trete demann:

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

Si nou louvri nan navigatè a example.com, nou pral resevwa yon repons HTTPS "Bonjou, mond!"

Si ou bezwen plis detay konfigirasyon, Lè sa a, ou ta dwe itilize manadjè a autocert.Manager. Lè sa a, nou kreye pwòp egzanp http.Server nou an (jiska kounye a nou te itilize li pa default) epi ajoute manadjè a nan sèvè TLSConfig la:

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

Sa a se yon fason fasil pou aplike sipò HTTPS konplè ak renouvèlman sètifika otomatik.

Ajoute wout koutim

Routeur default ki enkli nan bibliyotèk estanda a bon, men li trè debaz. Pifò aplikasyon mande pou routage pi konplèks, ki gen ladan wout imbrike ak wildcard, oswa yon pwosedi pou mete modèl chemen ak paramèt.

Nan ka sa a li vo itilize pakè goril/mux и go-chi/chi. Nou pral aprann ki jan yo travay ak lèt ​​la - yon egzanp yo montre anba a.

Yo bay dosye api/v1/api.go ki gen wout pou API nou an:

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

Nou mete prefiks api/vq pou wout nan dosye prensipal la.

Lè sa a, nou ka monte sa a sou routeur prensipal nou an anba prefiks api/v1/ tounen nan aplikasyon prensipal nou an:

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

Fasilite Go nan travay ak wout konplèks fè li posib senplifye estriktirasyon an ak antretyen nan aplikasyon gwo, konplèks.

Travay ak middleware

Staging enplike nan vlope yon sèl HTTP handler ak yon lòt, ki fè li posib byen vit fè otantifikasyon, konpresyon, antre, ak plizyè lòt fonksyon.

Kòm yon egzanp, ann gade nan koòdone http.Handler, nou pral sèvi ak li pou ekri yon moun k ap okipe sèvis yo otantifye itilizatè yo.

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

Gen routeurs twazyèm pati, tankou chi, ki pèmèt ou pwolonje fonksyonalite middleware la.

Travay ak fichye estatik

Bibliyotèk estanda Go a gen ladan kapasite pou travay ak kontni estatik, tankou imaj, JavaScript ak dosye CSS. Yo ka jwenn aksè nan fonksyon http.FileServer. Li retounen yon moun k ap okipe dosye ki soti nan yon anyè espesifik.

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

Li se definitivman vo sonje ke http.Dir montre sa ki nan anyè a si li pa genyen dosye prensipal la index.html. Nan ka sa a, pou anpeche anyè a konpwomèt, ou ta dwe itilize pake a unindexed.

Fèmen kòrèk

Go tou gen yon karakteristik ki rele grasyeuz fèmen nan sèvè HTTP a. Sa a ka fè lè l sèvi avèk metòd la Shutdown (). Se sèvè a te kòmanse nan yon goroutine, ak Lè sa a, se kanal la koute resevwa yon siyal entèwonp. Le pli vit ke yo resevwa siyal la, sèvè a fèmen, men se pa imedyatman, men apre kèk segonn.

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)

Kòm yon konklizyon

Go se yon lang pwisan ak yon bibliyotèk estanda prèske inivèsèl. Kapasite default li yo trè laj, epi yo ka amelyore lè l sèvi avèk interfaces - sa a pèmèt ou devlope sèvè HTTP vrèman serye.

Skillbox rekòmande:

Sous: www.habr.com

Add nouvo kòmantè