Golanqda veb serverlərin hazırlanması - sadədən mürəkkəbə

Golanqda veb serverlərin hazırlanması - sadədən mürəkkəbə

Beş il əvvəl başladım Gophish inkişaf etdirin, bu Qolanq öyrənmək imkanı verdi. Mən başa düşdüm ki, Go bir çox kitabxana ilə tamamlanan güclü bir dildir. Go çox yönlüdür: xüsusilə, heç bir problem olmadan server tərəfi proqramları hazırlamaq üçün istifadə edilə bilər.

Bu məqalə Go-da server yazmaq haqqındadır. “Salam dünya!” kimi sadə şeylərlə başlayaq və aşağıdakı imkanlara malik bir proqramla bitirək:

- HTTPS üçün Let's Encrypt istifadə.
— API marşrutlaşdırıcısı kimi işləyir.
- Orta proqram təminatı ilə işləmək.
— Statik faylların işlənməsi.
- Düzgün bağlanma.

Skillbox tövsiyə edir: Praktik kurs "Sıfırdan Python tərtibçisi".

Xatırladırıq: "Habr" ın bütün oxucuları üçün - "Habr" promosyon kodundan istifadə edərək hər hansı bir Skillbox kursuna yazılarkən 10 000 rubl endirim.

Salam dünya!

Siz Go-da çox tez veb server yarada bilərsiniz. Yuxarıda vəd edilmiş “Salam, dünya!” qaytaran bir işləyicidən istifadə nümunəsidir.

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 işə salıb səhifəni açsanız localhost, onda siz dərhal “Salam, dünya!” mətnini görəcəksiniz. (əgər hər şey düzgün işləyirsə, əlbəttə).

İşləyicidən bir neçə dəfə sonra istifadə edəcəyik, lakin əvvəlcə hər şeyin necə işlədiyini anlayaq.

net/http

Nümunə paketdən istifadə etdi net/http, həm serverləri, həm də HTTP müştərilərini inkişaf etdirmək üçün Go-da əsas vasitədir. Kodu başa düşmək üçün üç mühüm elementin mənasını anlayaq: http.Handler, http.ServeMux və http.Server.

HTTP işləyiciləri

Biz sorğu aldıqda, işləyici onu təhlil edir və cavab yaradır. Go-da işləyicilər aşağıdakı kimi həyata keçirilir:

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

Birinci nümunə http.HandleFunc köməkçi funksiyasından istifadə edir. O, başqa bir funksiyanı əhatə edir, bu da öz növbəsində http.ResponseWriter və http.Request-i ServeHTTP-yə götürür.

Başqa sözlə, Golanqdakı işləyicilər proqramçıya çoxlu seçimlər verən vahid interfeysdə təqdim olunur. Beləliklə, məsələn, ara proqram bir işləyicidən istifadə edərək həyata keçirilir, burada ServeHTTP əvvəlcə bir şey edir və sonra başqa bir işləyicinin ServeHTTP metodunu çağırır.

Yuxarıda qeyd edildiyi kimi, işləyicilər sadəcə sorğulara cavablar yaradırlar. Ancaq müəyyən bir zamanda hansı xüsusi işləyicidən istifadə edilməlidir?

Marşrutlaşdırma sorğusu

Düzgün seçim etmək üçün HTTP multipleksorundan istifadə edin. Bir sıra kitabxanalarda ona muxer və ya marşrutlaşdırıcı deyilir, lakin onların hamısı eyni şeydir. Multipleksorun funksiyası sorğu yolunu təhlil etmək və müvafiq işləyicini seçməkdir.

Mürəkkəb marşrutlaşdırma üçün dəstəyə ehtiyacınız varsa, üçüncü tərəf kitabxanalarından istifadə etmək daha yaxşıdır. Ən qabaqcıllardan bəziləri - qorilla/mux и go-chi/chi, bu kitabxanalar heç bir problem olmadan aralıq emal həyata keçirməyə imkan verir. Onların köməyi ilə siz wildcard marşrutunu konfiqurasiya edə və bir sıra digər tapşırıqları yerinə yetirə bilərsiniz. Onların üstünlüyü standart HTTP işləyiciləri ilə uyğunluqdur. Nəticədə, gələcəkdə dəyişdirilə bilən sadə kod yaza bilərsiniz.

Normal vəziyyətdə mürəkkəb çərçivələrlə işləmək qeyri-standart həllər tələb edəcək və bu, standart işləyicilərin istifadəsini əhəmiyyətli dərəcədə çətinləşdirir. Tətbiqlərin böyük əksəriyyətini yaratmaq üçün standart kitabxana və sadə marşrutlaşdırıcının birləşməsi kifayət edəcəkdir.

Sorğunun emalı

Bundan əlavə, bizə daxil olan əlaqələri "dinləyəcək" və bütün sorğuları düzgün işləyiciyə yönləndirəcək bir komponent lazımdır. http.Server bu işi asanlıqla idarə edə bilər.

Aşağıdakılar serverin əlaqənin işlənməsi ilə bağlı bütün tapşırıqlara cavabdeh olduğunu göstərir. Bu, məsələn, TLS protokolundan istifadə etməklə işləyir. http.ListenAndServer çağırışını həyata keçirmək üçün standart HTTP serverindən istifadə olunur.

İndi daha mürəkkəb nümunələrə baxaq.

Let's Encrypt əlavə edilir

Varsayılan olaraq, tətbiqimiz HTTP protokolu üzərində işləyir, lakin HTTPS protokolundan istifadə etmək tövsiyə olunur. Bu, Go-da problem olmadan edilə bilər. Əgər siz sertifikat və şəxsi açar almısınızsa, o zaman ListenAndServeTLS-i düzgün sertifikat və açar faylları ilə qeydiyyatdan keçirməyiniz kifayətdir.

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

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

Şifrə verək avtomatik yenilənmə ilə pulsuz sertifikatlar təqdim edir. Xidmətdən istifadə etmək üçün sizə paket lazımdır autocert.

Onu konfiqurasiya etməyin ən asan yolu http.Serve ilə birlikdə autocert.NewListener metodundan istifadə etməkdir. Metod HTTP serveri sorğuları emal edərkən TLS sertifikatlarını əldə etməyə və yeniləməyə imkan verir:

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

Brauzerdə açsaq example.com, biz “Salam, dünya!” HTTPS cavabını alacağıq.

Daha ətraflı konfiqurasiyaya ehtiyacınız varsa, autocert.Manager menecerindən istifadə etməlisiniz. Sonra öz http.Server nümunəmizi yaradırıq (indiyə qədər biz ondan standart olaraq istifadə edirik) və meneceri TLSConfig serverinə ə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, avtomatik sertifikat yenilənməsi ilə tam HTTPS dəstəyini həyata keçirməyin asan yoludur.

Fərdi marşrutların əlavə edilməsi

Standart kitabxanaya daxil edilmiş standart marşrutlaşdırıcı yaxşıdır, lakin çox sadədir. Əksər proqramlar daha mürəkkəb marşrutlaşdırma tələb edir, o cümlədən iç-içə və wildcard marşrutları və ya yol nümunələri və parametrləri təyin etmək üçün prosedur.

Bu vəziyyətdə paketlərdən istifadə etməyə dəyər qorilla/mux и go-chi/chi. Sonuncu ilə necə işləməyi öyrənəcəyik - bir nümunə aşağıda göstərilmişdir.

API üçün marşrutları ehtiva edən api/v1/api.go faylı verilmişdir:

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

Əsas faylda marşrutlar üçün api/vq prefiksini təyin etdik.

Sonra bunu əsas tətbiqimizdə api/v1/ prefiksi altında əsas marşrutlaşdırıcımıza quraşdıra 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-nun mürəkkəb marşrutlarla işləmək asanlığı böyük, mürəkkəb proqramların strukturlaşdırılmasını və texniki xidmətini sadələşdirməyə imkan verir.

Orta proqram təminatı ilə işləmək

Səhnələşdirmə bir HTTP işləyicisini digəri ilə bağlamaqdan ibarətdir ki, bu da autentifikasiya, sıxılma, giriş və bir sıra digər funksiyaları tez yerinə yetirməyə imkan verir.

Nümunə olaraq, http.Handler interfeysinə baxaq, biz ondan xidmət istifadəçilərinin autentifikasiyasını həyata keçirən işləyici yazmaq üçün istifadə edəcəyik.

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

Orta proqram funksiyasını genişləndirməyə imkan verən chi kimi üçüncü tərəf marşrutlaşdırıcıları var.

Statik fayllarla işləmək

Go standart kitabxanasına şəkillər, JavaScript və CSS faylları daxil olmaqla statik məzmunla işləmək imkanları daxildir. Onlara http.FileServer funksiyası vasitəsilə daxil olmaq olar. Müəyyən bir kataloqdan fayllara xidmət edən işləyicini qaytarır.

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

Mütləq xatırlamağa dəyər ki, http.Dir kataloqun məzmununu göstərir, əgər onda əsas index.html faylı yoxdursa. Bu halda, kataloqun təhlükəyə məruz qalmasının qarşısını almaq üçün paketdən istifadə etməlisiniz unindexed.

Düzgün bağlanma

Go həmçinin HTTP serverinin zərif bağlanması adlı xüsusiyyətə malikdir. Bu, Shutdown() metodundan istifadə etməklə edilə bilər. Server goroutine-də işə salınır və sonra kəsilmə siqnalı almaq üçün kanal dinlənilir. Siqnal qəbul edilən kimi server sönür, lakin dərhal deyil, bir neçə saniyədən sonra.

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)

Nəticə olaraq

Go demək olar ki, universal standart kitabxanası olan güclü bir dildir. Onun standart imkanları çox genişdir və onlar interfeyslərdən istifadə etməklə təkmilləşdirilə bilər - bu, həqiqətən etibarlı HTTP serverlərini inkişaf etdirməyə imkan verir.

Skillbox tövsiyə edir:

Mənbə: www.habr.com

Добавить комментарий