Golang-da veb-serverlərin hazırlanması — sadədən mürəkkəblərə

Golang-da veb-serverlərin hazırlanması — sadədən mürəkkəblərə

Beş il əvvəl Gophish inkişaf etməyə başladım , bu, Golang-ı öyrənmək imkanı verdi. Anladım ki, Go güclü bir dildir, imkanları çoxlu kitabxanalarla tamamlanır. Go universaldır: xüsusilə, onunla problemsiz server tətbiqləri inkişaf etdirmək mümkündür.Bu məqalə Go-da server yazmağa həsr olunub. Sadə şeylərlə, məsələn, "Hello world!"-dan başlayıb, aşağıdakı imkanlara malik bir tətbiqlə bitirəcəyik:

— HTTPS üçün Let’s Encrypt istifadə.

— API marşrutçusu kimi işləmək.
— Middleware ilə işləmək.
— Statik faylları emal etmək.
— Düzgün şəkildə bağlanma.
«S нуль Python разработчик»

Skillbox tövsiyə edir: Praktik kurs Hello, world!.

Xatırladırıq: bütün «Habr» oxucularına — «Habr» promo kodu ilə Skillbox-dakı hər hansı kursa qeydiyyat zamanı 10 000 rubl endirim.

Go-da veb server yaratmaq olduqca sürətlidir. Budur yuxarıda vəd edilən "Hello, world!"-i qaytaran bir işləyici nümunəsi.

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

Bundan sonra, tətbiqi başladıb səhifəni açsanız, dərhal "Hello, world!" mətni görünəcək (əlbəttə ki, hər şey düzgün işləyirsə).

Sonra işləyicini dəfələrlə istifadə edəcəyik, amma əvvəlcə gəlin hər şeyin necə təşkil olunduğunu başa düşək. localhostnet/http

Nümunədə istifadə edilən paket

, bu, Go-da həm server, həm də HTTP müştəriləri üçün əsas vasitədir. Kodu başa düşmək üçün üç vacib elementin mənasını araşdıraq: http.Handler, http.ServeMux və http.Server.

HTTP işləyiciləri , bu, Go-da həm server, həm də HTTP müştəriləri üçün əsas vasitədir. Kodu başa düşmək üçün üç vacib elementin mənasını araşdıraq: http.Handler, http.ServeMux və http.Server.Sorğu aldığımızda, işləyici onu analiz edir və cavab formalaşdırır. Go-da işləyicilər aşağıdakı şəkildə həyata keçirilir:

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

Birinci nümunədə http.HandleFunc köməkçi funksiyası istifadə edilir. Bu, başqa bir funksiyanı bükür ki, bu funksiya da öz növbəsində http.ResponseWriter və http.Request-i ServeHTTP-da qəbul edir.

Başqa sözlə, Golang-da işləyicilər tək interfeys olaraq təqdim edilir ki, bu da proqramçıya çoxlu imkanlar yaradır. Məsələn, middleware bir işləyici vasitəsilə həyata keçirilir; burada ServeHTTP əvvəlcə nəsə edir, sonra isə başqa bir işlədicinin ServeHTTP metodunu çağırır.

Yuxarıda qeyd edildiyi kimi, işləyicilər sadəcə sorğulara cavab formalaşdırır. Amma konkret bir anda hansı işləyicinin seçilməli olduğunu necə müəyyən etməliyik?

Sorğuların marşrutlaşdırılması

Doğru seçimi etmək üçün HTTP multiplexorundan istifadə edin. Bir sıra kitabxanalarda ona muxer və ya router deyilir, amma bunların hamısı eynidir. Multiplexorun funksiyası sorğu yolunu analiz etmək və uyğun işləyicini seçməkdir.

Əgər mürəkkəb marşrutlaşdırma dəstəyi tələb olunursa, o zaman üçüncü tərəf kitabxanalarından istifadə etmək daha yaxşıdır. Ən inkişaf etmişlərindən bəziləri —

gorilla/mux

go-chi/chi gorilla/muxgo-chi/chi, bu kitabxanalar aralıq emalını asanlıqla həyata keçirmək imkanı yaradır. Onların köməyi ilə wildcard yönləndirmələr qurmaq və bir sıra digər tapşırıqları yerinə yetirmək mümkündür. Onların üstünlüyü - standart HTTP emalçıları ilə uyğunluqdur. Nəticədə, siz gələcəkdə dəyişdirilə bilən sadə kod yazmaq imkanına malik olursunuz.

Mürəkkəb çərçivələrlə işləmək adətən standart olmayan həllər tələb edəcək, bu da standart emalçıların istifadəsini xeyli çətinləşdirir. Əksər tətbiqləri yaratmaq üçün standart kitabxana ilə sadə yönləndirmə kombinasiyası kifayət edir.

Sorğuların emalı

Bundan əlavə, daxil olan əlaqələri "dinləyən" və bütün sorğuları doğru emalçıya yönləndirmək üçün bir komponentə ehtiyacımız var. Bu tapşırıqla http.Server asanlıqla başa çıxır.

Aşağıda göstərilir ki, server bağlantıların emalı ilə bağlı bütün tapşırıqlara cavabdehdir. Məsələn, TLS protokolunda işləmək. http.ListenAndServer çağırışının həyata keçirilməsi standart HTTP serverindən istifadə edir.

İndi isə daha mürəkkəb nümunələrə nəzər salaq.

Let’s Encrypt əlavə etmək

Standart olaraq, tətbiqimiz HTTP protokolunda işləyir, lakin HTTPS protokolundan istifadə etməyi tövsiyə edirik. Go-da bunu asanlıqla edə bilərsiniz. Şertifikat və özəl açar əldə etdikdə, ListenAndServeTLS çağırışını düzgün sertifikat və açar fayllarını göstərməklə yerinə yetirmək kifayətdir.

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

Həmişə daha yaxşısını edə bilərsiniz.

Let’s Encrypt avtomatik yeniləmə imkanı ilə pulsuz sertifikatlar təqdim edir. Xidmətin istifadəsi üçün paketə ehtiyac var: autocert.

Onu qurmağın ən asan yolu autocert.NewListener metodundan istifadə etmək və http.Serve ilə birləşdirməkdir. Bu metod TLS sertifikatlarını əldə etməyə və yeniləməyə imkan verir, eyni zamanda HTTP serveri sorğuları emal edir:

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

Brahuzerdə açdığımızda, example.com, HTTPS cavabı olaraq "Salam, dünya!" alırıq.

Əgər daha ətraflı konfiqurasiya edilməsi lazımdırsa, autocert.Manager menecerindən istifadə etməlisiniz. Sonra öz http.Server instansiyalarımızı yaradırıq (indiyədək standartını istifadə edirdik) və meneceri serverin TLSConfig-ə əlavə edirik:

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

Bu, sertifikatın avtomatik yenilənməsi ilə HTTPS-in tam dəstəklənməsinin həyata keçirilməsi üçün sadə bir yoldur.

Qeyri-standart yönləndirmələr əlavə etmək

Standart kitabxanaya daxil edilmiş defolt yönləndirici yaxşıdır, lakin çox sadədir. Çoxsaylı tətbiqlərdə daha mürəkkəb yönləndirmələr lazım olacaq, daxil edilmiş və wildcard yönləndirmələr də daxil olmaqla və ya şablonların və yol parametrlərinin qurulması proseduru.

Bu halda, paketlərdən istifadə etmək lazımdır. gorilla/muxgo-chi/chi. Sonuncusu ilə işləməyi öyrənəcəyik — aşağıda bir nümunə təqdim edilir.

Verilmiş — api/v1/api.go faylı, API'miz üçün marşrutları ehtiva edir:

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

Marşrutlar üçün api/vq prefiksi əsas faylda müəyyən edilir.

Sonra bunu əsas tətbiqimizdə api/v1/ prefiksi altında öz əsas routerimizə qoşa bilərik:

// 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-da mürəkkəb marşrutlarla işləmək asanlığı, böyük kompleks tətbiqlərin, strukturlaşdırılmasını sadələşdirmək üçün mümkündür.

Middleware ilə işləmək

Aralıq emal zamanı bir HTTP-emalçısını digərinin ətrafında sarılmaq istifadə olunur, bu, çox tez bir zamanda autentifikasiya, sıxılma, jurnalizasyon və bəzi digər funksiyaların keçirilməsinə imkan verir.

Məsələn, http.Handler interfeysini götürək, bu vasitəsilə xidmətin istifadəçi autentifikasiyası ilə emalçı yazaq.

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
        }
        // Autentifikasiya keçildiyi halda, orijinal emalçını icra et
        next.ServeHTTP(w, r)
    })
}

Məsələn, chi kimi üçüncü tərəf marşrutçıları aralıq emal funksionallığını genişləndirmək üçün imkanı verir.

Statik fayllarla işləmək

Go-nun standart kitabxanasında statik məzmunla, o cümlədən şəkillərlə, JavaScript və CSS faylları ilə işləmək imkanları daxildir. Bunlara http.FileServer funksiyası vasitəsilə daxil olmaq mümkündür. Bu, müəyyən bir kateqoriyadan faylları paylayan bir emalçı geri qaytarır.

func NewRouter() http.Handler {
    router := chi.NewRouter()
    r.Get("/{name}", HelloName)
 
// Statik faylların paylanmasını konfiqurasiya et
staticPath, _ := filepath.Abs("../../static/")
fs := http.FileServer(http.Dir(staticPath))
    router.Handle("/*", fs)
    
    return r

Unutmaq olmaz ki, http.Dir, yalnızca əsas index.html faylı olmayan halda, kataloqun məzmununu çıxarır. Bu halda, katalogun kompromisə uğramaması üçün paketin istifadəsi mütləqdir. unindexed.

Düzgün dayandırma

Go-da HTTP-serverin düzgün dayandırılması üçün belə bir funksiya da mövcuddur. Bu, Shutdown() metodu vasitəsi ilə edilə bilər. Server bir goroutine-də işə başlayır və sonra bir siqnal dinləyici çənlənir. Siqnal alındıqda, server dərhal dayandırılmır, amma bir neçə saniyə sonra dayandırılır.

handler := server.NewRouter()
srv := &http.Server{
    Handler: handler,
}
 
go func() {
srv.Serve(autocert.NewListener(domains...))
}()
 
// Bir kəsilmə üçün gözləyin
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt)
<-c
 
// Düzgün dayandırma cəhdi
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
srv.Shutdown(ctx)

Nəticə olaraq

Go — demək olar ki, universal standart kitabxanası olan güclü bir dildir. Onun standart imkanları kifayət qədər genişdir və interfeyslər vasitəsilə onları gücləndirmək mümkündür — bu, həqiqətən etibarlı HTTP-serverlərinin inkişafına imkan verir.

Skillbox tövsiyə edir:

Mənbə: habr.com

DDoS mühafizəsi ilə vebsaytlar üçün etibarlı hosting satın alın, VPS VDS serverlər 🔥 DDoS mühafizəsi ilə vebsaytlar üçün etibarlı hosting satın alın, VPS VDS serverlər | ProHoster