Web serveru izstrāde Golangā - no vienkārŔas līdz sarežģītai

Web serveru izstrāde Golangā - no vienkārŔas līdz sarežģītai

Pirms pieciem gadiem es sāku izstrādāt Gophish, tas sniedza iespēju apgÅ«t Golangu. Es sapratu, ka Go ir spēcÄ«ga valoda, ko papildina daudzas bibliotēkas. Go ir daudzpusÄ«gs: jo Ä«paÅ”i to var izmantot, lai bez problēmām izstrādātu servera puses lietojumprogrammas.

Å is raksts ir par servera rakstÄ«Å”anu programmā Go. Sāksim ar vienkārŔām lietām, piemēram, "Sveika pasaule!", un beigsim ar lietojumprogrammu ar Ŕādām iespējām:

- Izmantojot Let's Encrypt HTTPS.
ā€” Darbs kā API marÅ”rutētājs.
ā€” Darbs ar starpprogrammatÅ«ru.
ā€” Statisko failu apstrāde.
ā€” Pareiza izslēgÅ”ana.

Skillbox iesaka: Praktiskais kurss "Python izstrādātājs no nulles".

Atgādinām: visiem "Habr" lasītājiem - atlaide 10 000 rubļu, reģistrējoties jebkurā Skillbox kursā, izmantojot "Habr" reklāmas kodu.

Sveika pasaule!

Programmā Go varat izveidot tÄ«mekļa serveri ļoti ātri. Å eit ir piemērs, kā izmantot apdarinātāju, kas atgriež iepriekÅ” apsolÄ«to ā€œSveika, pasaule!ā€.

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

Pēc tam, ja palaižat lietojumprogrammu un atverat lapu localhost, tad uzreiz redzēsit tekstu ā€œSveika, pasaule!ā€ (ja viss darbojas pareizi, protams).

Vēlāk mēs izmantosim apdarinātāju vairākas reizes, taču vispirms sapratīsim, kā viss darbojas.

net/http

Piemērā izmantota pakotne net/http, tas ir galvenais Go rīks gan serveru, gan HTTP klientu izstrādei. Lai saprastu kodu, sapratīsim trīs svarīgu elementu nozīmi: http.Handler, http.ServeMux un http.Server.

HTTP apstrādātāji

Kad mēs saņemam pieprasÄ«jumu, apstrādātājs to analizē un Ä£enerē atbildi. Apdarinātāji pakalpojumā Go tiek ieviesti Ŕādi:

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

Pirmajā piemērā tiek izmantota http.HandleFunc palīga funkcija. Tas ietver citu funkciju, kas savukārt pārņem http.ResponseWriter un http.Request pakalpojumā ServeHTTP.

Citiem vārdiem sakot, Golang apstrādātāji tiek parādīti vienā saskarnē, kas programmētājam sniedz daudz iespēju. Tā, piemēram, starpprogrammatūra tiek ieviesta, izmantojot apdarinātāju, kur ServeHTTP vispirms kaut ko dara un pēc tam izsauc cita apdarinātāja ServeHTTP metodi.

Kā minēts iepriekÅ”, apstrādātāji vienkārÅ”i Ä£enerē atbildes uz pieprasÄ«jumiem. Bet kurÅ” konkrēts apdarinātājs bÅ«tu jāizmanto konkrētā brÄ«dÄ«?

Pieprasīt marŔrutēŔanu

Lai izdarÄ«tu pareizo izvēli, izmantojiet HTTP multipleksoru. Daudzās bibliotēkās to sauc par muxer vai router, taču tie visi ir viens un tas pats. Multipleksera funkcija ir analizēt pieprasÄ«juma ceļu un izvēlēties atbilstoÅ”o apstrādātāju.

Ja jums ir nepiecieÅ”ams atbalsts sarežģītai marÅ”rutÄ“Å”anai, labāk ir izmantot treÅ”o puÅ”u bibliotēkas. Daži no vismodernākajiem - gorilla/mux Šø go-chi/chi, Ŕīs bibliotēkas ļauj bez problēmām Ä«stenot starpapstrādi. Ar viņu palÄ«dzÄ«bu jÅ«s varat konfigurēt aizstājējzÄ«mju marÅ”rutÄ“Å”anu un veikt vairākus citus uzdevumus. To priekÅ”rocÄ«ba ir saderÄ«ba ar standarta HTTP apstrādātājiem. Rezultātā jÅ«s varat uzrakstÄ«t vienkārÅ”u kodu, ko nākotnē var mainÄ«t.

Strādājot ar sarežģītiem ietvariem normālā situācijā, bÅ«s nepiecieÅ”ami nestandarta risinājumi, un tas bÅ«tiski apgrÅ«tina noklusējuma apstrādātāju izmantoÅ”anu. Lai izveidotu lielāko daļu lietojumprogrammu, pietiks ar noklusējuma bibliotēkas un vienkārÅ”a marÅ”rutētāja kombināciju.

Vaicājumu apstrāde

Turklāt mums ir nepiecieÅ”ams komponents, kas ā€œnoklausÄ«siesā€ ienākoÅ”os savienojumus un novirzÄ«s visus pieprasÄ«jumus uz pareizo apstrādātāju. http.Serveris var viegli tikt galā ar Å”o uzdevumu.

Tālāk redzams, ka serveris ir atbildīgs par visiem uzdevumiem, kas saistīti ar savienojuma apstrādi. Tas, piemēram, darbojas, izmantojot TLS protokolu. Lai ieviestu http.ListenAndServer izsaukumu, tiek izmantots standarta HTTP serveris.

Tagad apskatīsim sarežģītākus piemērus.

Pievienojot Let's Encrypt

Pēc noklusējuma mūsu lietojumprogramma darbojas, izmantojot HTTP protokolu, taču ieteicams izmantot HTTPS protokolu. To var izdarīt bez problēmām Go. Ja esat saņēmis sertifikātu un privāto atslēgu, tad pietiek reģistrēt ListenAndServeTLS ar pareizajiem sertifikāta un atslēgu failiem.

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

Jūs vienmēr varat darīt labāk.

Let's Encrypt nodroŔina bezmaksas sertifikātus ar automātisku atjaunoŔanu. Lai izmantotu pakalpojumu, nepiecieŔama pakete autocert.

VienkārŔākais veids, kā to konfigurēt, ir izmantot autocert.NewListener metodi kombinācijā ar http.Serve. Å Ä« metode ļauj iegÅ«t un atjaunināt TLS sertifikātus, kamēr HTTP serveris apstrādā pieprasÄ«jumus:

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

Ja atveram pārlūkprogrammā example.com, mēs saņemsim HTTPS atbildi "Sveika, pasaule!"

Ja nepiecieÅ”ama detalizētāka konfigurācija, tad jāizmanto autocert.Manager pārvaldnieks. Pēc tam mēs izveidojam savu http.Server instanci (lÄ«dz Å”im mēs to izmantojām pēc noklusējuma) un pievienojam pārvaldnieku TLSConfig serverim:

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

Tas ir vienkārŔs veids, kā ieviest pilnu HTTPS atbalstu ar automātisku sertifikātu atjaunoŔanu.

Pielāgotu marŔrutu pievienoŔana

Standarta bibliotēkā iekļautais noklusējuma marÅ”rutētājs ir labs, taču tas ir ļoti vienkārÅ”s. Lielākajai daļai lietojumprogrammu ir nepiecieÅ”ama sarežģītāka marÅ”rutÄ“Å”ana, tostarp ligzdoti un aizstājējzÄ«mju marÅ”ruti, vai procedÅ«ra ceļu modeļu un parametru iestatÄ«Å”anai.

Å ajā gadÄ«jumā ir vērts izmantot paketes gorilla/mux Šø go-chi/chi. Mēs uzzināsim, kā strādāt ar pēdējo - piemērs ir parādÄ«ts zemāk.

Ir dots fails api/v1/api.go, kurā ir mūsu API marŔruti:

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

Mēs iestatām api/vq prefiksu marÅ”rutiem galvenajā failā.

Pēc tam mēs to varam pievienot mÅ«su galvenajam marÅ”rutētājam ar prefiksu api/v1/ atpakaļ mÅ«su galvenajā lietojumprogrammā:

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

Go vienkārÅ”ais darbs ar sarežģītiem marÅ”rutiem ļauj vienkārÅ”ot lielu, sarežģītu lietojumu strukturÄ“Å”anu un uzturÄ“Å”anu.

Darbs ar starpprogrammatūru

UzstādÄ«Å”ana ietver viena HTTP apdarinātāja iesaiņoÅ”anu ar citu, ļaujot ātri veikt autentifikāciju, saspieÅ”anu, reÄ£istrÄ“Å”anu un vairākas citas funkcijas.

Piemēram, aplūkosim http.Handler saskarni; mēs to izmantosim, lai uzrakstītu apdarinātāju, kas autentificē pakalpojuma lietotājus.

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

Ir treÅ”o puÅ”u marÅ”rutētāji, piemēram, chi, kas ļauj paplaÅ”ināt starpprogrammatÅ«ras funkcionalitāti.

Darbs ar statiskiem failiem

Go standarta bibliotēkā ir iekļautas iespējas darbam ar statisku saturu, tostarp attēliem, JavaScript un CSS failiem. Tiem var piekļūt, izmantojot funkciju http.FileServer. Tas atgriež apstrādātāju, kas apkalpo failus no noteikta direktorija.

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

Noteikti der atcerēties, ka http.Dir parāda direktorijas saturu, ja tajā nav galvenā index.html faila. Å ajā gadÄ«jumā, lai novērstu direktorija uzlauzÅ”anu, jums vajadzētu izmantot pakotni unindexed.

Pareiza izslēgÅ”ana

Go ir arÄ« funkcija, ko sauc par HTTP servera graciozu izslēgÅ”anu. To var izdarÄ«t, izmantojot Shutdown() metodi. Serveris tiek palaists gorutÄ«nā, un pēc tam tiek klausÄ«ts kanāls, lai saņemtu pārtraukuma signālu. TiklÄ«dz tiek saņemts signāls, serveris izslēdzas, bet ne uzreiz, bet pēc dažām sekundēm.

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ā secinājums

Go ir spēcÄ«ga valoda ar gandrÄ«z universālu standarta bibliotēku. Tā noklusējuma iespējas ir ļoti plaÅ”as, un tās var uzlabot, izmantojot saskarnes ā€“ tas ļauj izstrādāt patiesi uzticamus HTTP serverus.

Skillbox iesaka:

Avots: www.habr.com

Pievieno komentāru