Развој на веб-сервер во Голанг - од едноставен до сложен

Развој на веб-сервер во Голанг - од едноставен до сложен

Пред пет години почнав развие гофиш, ова даде можност да се научи Голанг. Сфатив дека Go е моќен јазик, надополнет со многу библиотеки. Go е разноврсна: особено, може да се користи за развој на апликации од страна на серверот без никакви проблеми.

Оваа статија е за пишување сервер во Go. Да почнеме со едноставни работи како „Здраво свет!“ и да завршиме со апликација со следните можности:

- Користење на Let's Encrypt за HTTPS.
— Работи како API рутер.
— Работа со среден софтвер.
— Обработка на статични датотеки.
- Правилно исклучување.

Skillbox препорачува: Практичен курс „Програмер на Python од нула“.

Потсетуваме: за сите читатели на „Хабр“ - попуст од 10 рубли при запишување на кој било курс Skillbox користејќи го промотивниот код „Хабр“.

Здраво свету!

Можете многу брзо да креирате веб-сервер во Go. Еве пример за користење на управувач што го враќа „Здраво, свето!“ ветено погоре.

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

По ова, ако ја извршите апликацијата и ја отворите страницата localhost, тогаш веднаш ќе го видите текстот „Здраво, свето!“ (ако сè работи правилно, се разбира).

Ќе го користиме управувачот повеќе пати подоцна, но прво да разбереме како функционира сè.

нето/http

Примерот го користеше пакетот net/http, тоа е примарна алатка во Go за развој на сервери и HTTP клиенти. За да го разбереме кодот, да го разбереме значењето на три важни елементи: http.Handler, http.ServeMux и http.Server.

Ракувачи на HTTP

Кога ќе добиеме барање, управувачот го анализира и генерира одговор. Ракувачите во Go се имплементирани на следниов начин:

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

Првиот пример ја користи помошната функција http.HandleFunc. Таа обвива друга функција, која пак ги зема http.ResponseWriter и http.Request во ServeHTTP.

Со други зборови, управувачите во Golang се претставени во еден интерфејс, што му дава многу опции на програмерот. Така, на пример, средниот софтвер се имплементира со помош на управувач, каде што ServeHTTP прво прави нешто, а потоа го повикува методот ServeHTTP на друг управувач.

Како што споменавме погоре, управувачите едноставно генерираат одговори на барањата. Но, кој конкретен управувач треба да се користи во одреден момент во времето?

Побарајте рутирање

За да го направите вистинскиот избор, користете HTTP мултиплексер. Во голем број библиотеки се нарекува muxer или рутер, но сите тие се иста работа. Функцијата на мултиплексерот е да ја анализира патеката на барањето и да го избере соодветниот управувач.

Ако ви треба поддршка за сложено рутирање, тогаш подобро е да користите библиотеки од трети страни. Некои од најнапредните - горила/мукс и го-чи/чи, овие библиотеки овозможуваат имплементација на средна обработка без никакви проблеми. Со нивна помош, можете да го конфигурирате насочувањето на џокерите и да извршите голем број други задачи. Нивната предност е компатибилноста со стандардните HTTP ракувачи. Како резултат на тоа, можете да напишете едноставен код што може да се менува во иднина.

Работата со сложени рамки во нормална ситуација ќе бара нестандардни решенија, а тоа значително ја отежнува употребата на стандардните управувачи. За да креирате огромно мнозинство апликации, ќе биде доволна комбинација од стандардната библиотека и едноставен рутер.

Обработка на барања

Дополнително, потребна ни е компонента што ќе ги „слуша“ дојдовните врски и ќе ги пренасочи сите барања до правилниот управувач. http.Server лесно може да се справи со оваа задача.

Следното покажува дека серверот е одговорен за сите задачи кои се поврзани со обработката на конекцијата. Ова, на пример, работи со користење на протоколот TLS. За спроведување на повикот http.ListenAndServer, се користи стандарден HTTP сервер.

Сега да погледнеме посложени примери.

Додавање Let's Encrypt

Стандардно, нашата апликација работи преку протоколот HTTP, но се препорачува да се користи протоколот HTTPS. Ова може да се направи без проблеми во Go. Ако сте добиле сертификат и приватен клуч, тогаш доволно е да регистрирате ListenAndServeTLS со точниот сертификат и датотеки со клучеви.

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

Секогаш можете подобро.

Ајде да шифрираме обезбедува бесплатни сертификати со автоматско обновување. За да ја користите услугата, потребен ви е пакет autocert.

Најлесен начин да се конфигурира е да се користи методот autocert.NewListener во комбинација со http.Serve. Методот ви овозможува да добивате и ажурирате TLS сертификати додека серверот HTTP обработува барања:

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

Ако отвориме во прелистувачот example.com, ќе добиеме HTTPS одговор „Здраво, свет!

Ако ви треба подетална конфигурација, тогаш треба да го користите менаџерот autocert.Manager. Потоа креираме сопствен пример http.Server (до сега го користевме стандардно) и го додаваме менаџерот на серверот 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("", "")

Ова е лесен начин за спроведување целосна поддршка за HTTPS со автоматско обновување на сертификатот.

Додавање приспособени рути

Стандардниот рутер вклучен во стандардната библиотека е добар, но е многу основен. Повеќето апликации бараат покомплексно рутирање, вклучително и вгнездени правци и маршрути со букви, или постапка за поставување шеми и параметри на патеките.

Во овој случај вреди да се користат пакети горила/мукс и го-чи/чи. Ќе научиме како да работиме со второто - пример е прикажан подолу.

Дадена е датотеката api/v1/api.go која содржи правци за нашето API:

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

Го поставивме префиксот api/vq за маршрутите во главната датотека.

Потоа можеме да го монтираме ова на нашиот главен рутер под префиксот api/v1/ назад во нашата главна апликација:

// 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 за работа со сложени правци овозможува да се поедностави структурирањето и одржувањето на големи, сложени апликации.

Работа со среден софтвер

Степенот вклучува обвиткување на еден HTTP управувач со друг, што овозможува брзо извршување на автентикација, компресија, логирање и неколку други функции.

Како пример, да го погледнеме интерфејсот http.Handler; ќе го користиме за да напишеме управувач кој ги автентицира корисниците на услугите.

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

Постојат рутери од трети страни, како што е chi, кои ви дозволуваат да ја проширите функционалноста на среден софтвер.

Работа со статични датотеки

Стандардната библиотека Go вклучува можности за работа со статична содржина, вклучувајќи слики, JavaScript и CSS-датотеки. До нив може да се пристапи преку функцијата http.FileServer. Тој враќа управувач кој опслужува датотеки од одреден директориум.

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

Дефинитивно вреди да се запамети дека http.Dir ја прикажува содржината на директориумот ако не ја содржи главната датотека index.html. Во овој случај, за да спречите компромитирање на директориумот, треба да го користите пакетот unindexed.

Правилно исклучување

Go исто така има функција наречена грациозно исклучување на серверот HTTP. Ова може да се направи со помош на методот Shutdown(). Серверот се стартува во горутина, а потоа се слуша каналот за да се прими сигнал за прекин. Штом се прими сигналот, серверот се исклучува, но не веднаш, туку по неколку секунди.

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)

Како заклучок

Go е моќен јазик со речиси универзална стандардна библиотека. Неговите стандардни можности се многу широки и тие можат да се подобрат со помош на интерфејси - ова ви овозможува да развиете навистина сигурни HTTP сервери.

Skillbox препорачува:

Извор: www.habr.com

Додадете коментар