Ukuzaji wa seva ya wavuti huko Golang - kutoka rahisi hadi ngumu

Ukuzaji wa seva ya wavuti huko Golang - kutoka rahisi hadi ngumu

Miaka mitano iliyopita nilianza kuendeleza Gophish, hii ilitoa fursa ya kujifunza Kigolang. Niligundua kuwa Go ni lugha yenye nguvu, inayokamilishwa na maktaba nyingi. Go ni hodari: haswa, inaweza kutumika kutengeneza programu-tumizi za upande wa seva bila matatizo yoyote.

Nakala hii inahusu kuandika seva katika Go. Wacha tuanze na vitu rahisi kama vile "Hujambo ulimwengu!" na tumalizie na programu iliyo na uwezo ufuatao:

- Kutumia Let's Encrypt kwa HTTPS.
- Inafanya kazi kama kipanga njia cha API.
- Kufanya kazi na vifaa vya kati.
- Usindikaji wa faili tuli.
- Kuzima kwa usahihi.

Skillbox inapendekeza: Kozi ya vitendo "Mtengenezaji wa chatu kutoka mwanzo".

Tunakukumbusha: kwa wasomaji wote wa "Habr" - punguzo la rubles 10 wakati wa kujiandikisha katika kozi yoyote ya Skillbox kwa kutumia msimbo wa uendelezaji wa "Habr".

Habari, dunia!

Unaweza kuunda seva ya wavuti katika Go haraka sana. Huu hapa ni mfano wa kutumia kidhibiti ambacho hurejesha "Hujambo, ulimwengu!" ulioahidiwa hapo juu.

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

Baada ya hayo, ikiwa utaendesha programu na ufungue ukurasa lochost, basi utaona mara moja maandishi "Hujambo, ulimwengu!" (ikiwa kila kitu kitafanya kazi kwa usahihi, bila shaka).

Tutatumia kidhibiti mara nyingi baadaye, lakini kwanza tuelewe jinsi kila kitu kinavyofanya kazi.

wavu/http

Mfano ulitumia kifurushi net/http, ni zana ya msingi katika Go kwa kutengeneza seva na wateja wa HTTP. Ili kuelewa msimbo, hebu tuelewe maana ya vipengele vitatu muhimu: http.Handler, http.ServeMux na http.Server.

Vidhibiti vya HTTP

Tunapopokea ombi, kidhibiti hulichanganua na kutoa jibu. Vishughulikiaji katika Go vinatekelezwa kama ifuatavyo:

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

Mfano wa kwanza hutumia kitendakazi cha msaidizi wa http.HandleFunc. Hufunga kitendakazi kingine, ambacho kwa upande wake huchukua http.ResponseWriter na http.Request kwenye ServeHTTP.

Kwa maneno mengine, washughulikiaji katika Golang wanawasilishwa kwa kiolesura kimoja, ambacho kinatoa chaguzi nyingi kwa programu. Kwa hivyo, kwa mfano, vifaa vya kati vinatekelezwa kwa kutumia kidhibiti, ambapo ServeHTTP kwanza hufanya kitu kisha huita njia ya ServeHTTP ya kidhibiti kingine.

Kama ilivyoelezwa hapo juu, washughulikiaji hutoa tu majibu kwa maombi. Lakini ni kidhibiti kipi kinapaswa kutumiwa kwa wakati fulani?

Omba Uelekezaji

Ili kufanya chaguo sahihi, tumia HTTP multiplexer. Katika idadi ya maktaba inaitwa muxer au router, lakini wote ni kitu kimoja. Kazi ya multiplexer ni kuchambua njia ya ombi na kuchagua kidhibiti kinachofaa.

Ikiwa unahitaji usaidizi kwa uelekezaji mgumu, basi ni bora kutumia maktaba za watu wengine. Baadhi ya ya juu zaidi - gorila/mux ΠΈ go-chi/chi, maktaba hizi hufanya iwezekanavyo kutekeleza usindikaji wa kati bila matatizo yoyote. Kwa msaada wao, unaweza kusanidi uelekezaji wa kadi-mwitu na utekeleze idadi ya kazi zingine. Faida yao ni utangamano na vidhibiti vya kawaida vya HTTP. Matokeo yake, unaweza kuandika msimbo rahisi ambao unaweza kurekebishwa katika siku zijazo.

Kufanya kazi na mifumo ngumu katika hali ya kawaida itahitaji suluhisho zisizo za kawaida, na hii inatatiza sana utumiaji wa vidhibiti chaguo-msingi. Ili kuunda idadi kubwa ya programu, mchanganyiko wa maktaba chaguo-msingi na kipanga njia rahisi kitatosha.

Uchakataji wa Maswali

Kwa kuongeza, tunahitaji kijenzi ambacho "kitasikiliza" kwa miunganisho inayoingia na kuelekeza maombi yote kwa kidhibiti sahihi. http.Seva inaweza kushughulikia kazi hii kwa urahisi.

Ifuatayo inaonyesha kuwa seva inawajibika kwa kazi zote zinazohusiana na usindikaji wa unganisho. Hii, kwa mfano, inafanya kazi kwa kutumia itifaki ya TLS. Ili kutekeleza simu ya http.ListenAndServer, seva ya kawaida ya HTTP inatumiwa.

Sasa hebu tuangalie mifano ngumu zaidi.

Kuongeza Hebu Tusimbe

Kwa chaguo-msingi, programu yetu inaendesha itifaki ya HTTP, lakini inashauriwa kutumia itifaki ya HTTPS. Hii inaweza kufanyika bila matatizo katika Go. Ikiwa umepokea cheti na ufunguo wa kibinafsi, basi inatosha kusajili ListenAndServeTLS na cheti sahihi na faili muhimu.

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

Unaweza kufanya vizuri zaidi kila wakati.

Hebu Turuhusu hutoa vyeti vya bure na usasishaji kiotomatiki. Ili kutumia huduma, unahitaji kifurushi autocert.

Njia rahisi zaidi ya kuisanidi ni kutumia njia ya autocert.NewListener pamoja na http.Serve. Mbinu hukuruhusu kupata na kusasisha vyeti vya TLS wakati seva ya HTTP inachakata ombi:

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

Ikiwa tutafungua kwenye kivinjari example.com, tutapokea jibu la HTTPS "Hujambo, ulimwengu!"

Ikiwa unahitaji usanidi wa kina zaidi, basi unapaswa kutumia meneja wa autocert.Manager. Kisha tunaunda mfano wetu wa http.Seva (mpaka sasa tuliitumia kwa chaguo-msingi) na kuongeza kidhibiti kwenye seva ya 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("", "")

Hii ni njia rahisi ya kutekeleza usaidizi kamili wa HTTPS kwa kusasisha cheti kiotomatiki.

Inaongeza njia maalum

Router chaguo-msingi iliyojumuishwa kwenye maktaba ya kawaida ni nzuri, lakini ni ya msingi sana. Programu nyingi zinahitaji uelekezaji changamano zaidi, ikijumuisha njia zilizowekwa kiota na kadi-mwitu, au utaratibu wa kuweka mifumo na vigezo vya njia.

Katika kesi hii ni thamani ya kutumia vifurushi gorila/mux ΠΈ go-chi/chi. Tutajifunza jinsi ya kufanya kazi na mwisho - mfano umeonyeshwa hapa chini.

Imepewa faili api/v1/api.go iliyo na njia za API yetu:

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

Tunaweka kiambishi awali cha api/vq kwa njia kwenye faili kuu.

Kisha tunaweza kuweka hii kwenye kipanga njia chetu kikuu chini ya kiambishi awali cha api/v1/ katika programu yetu kuu:

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

Urahisi wa Go kufanya kazi na njia ngumu hufanya iwezekane kurahisisha uundaji na matengenezo ya programu kubwa na ngumu.

Kufanya kazi na vifaa vya kati

Uwekaji hatua unahusisha kufunga kidhibiti kimoja cha HTTP na kingine, na kuifanya iwezekane kutekeleza kwa haraka uthibitishaji, ukandamizaji, ukataji miti, na kazi zingine kadhaa.

Kama mfano, hebu tuangalie kiolesura cha http.Handler; tutakitumia kuandika kidhibiti kinachothibitisha watumiaji wa huduma.

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

Kuna vipanga njia vya watu wengine, kama vile chi, vinavyokuruhusu kupanua utendakazi wa programu ya kati.

Kufanya kazi na faili tuli

Maktaba ya kawaida ya Go inajumuisha uwezo wa kufanya kazi na maudhui tuli, ikiwa ni pamoja na picha, JavaScript na faili za CSS. Wanaweza kufikiwa kupitia http.FileServer kazi. Inarudisha kidhibiti ambacho hutumikia faili kutoka kwa saraka maalum.

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

Kwa hakika inafaa kukumbuka kuwa http.Dir inaonyesha yaliyomo kwenye saraka ikiwa haina faili kuu ya index.html. Katika kesi hii, ili kuzuia saraka kuathiriwa, unapaswa kutumia kifurushi unindexed.

Kuzima kwa usahihi

Go pia ina kipengele kinachoitwa kuzima kwa neema kwa seva ya HTTP. Hii inaweza kufanywa kwa kutumia Shutdown() njia. Seva imeanzishwa kwa njia ya kawaida, na kisha kituo kinasikilizwa ili kupokea ishara ya kukatiza. Mara tu ishara inapopokelewa, seva huzima, lakini si mara moja, lakini baada ya sekunde chache.

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)

Kama hitimisho

Go ni lugha yenye nguvu iliyo na takriban maktaba ya kawaida ya ulimwengu wote. Uwezo wake wa chaguo-msingi ni mpana sana, na unaweza kuimarishwa kwa kutumia miingiliano - hii hukuruhusu kukuza seva za HTTP zinazoaminika kweli.

Skillbox inapendekeza:

Chanzo: mapenzi.com

Kuongeza maoni