Голангда веб-серверди өнүктүрүү - жөнөкөйдөн татаалга чейин

Голангда веб-серверди өнүктүрүү - жөнөкөйдөн татаалга чейин

Беш жыл мурун мен баштаган Gophish иштеп чыгуу, бул Голанг үйрөнүүгө мүмкүнчүлүк берди. Мен Go көптөгөн китепканалар менен толукталган күчтүү тил экенин түшүндүм. Go ар тараптуу: атап айтканда, эч кандай көйгөйсүз сервердик тиркемелерди иштеп чыгуу үчүн колдонулушу мүмкүн.

Бул макала Go'до сервер жазуу жөнүндө. "Салам дүйнө!" сыяктуу жөнөкөй нерселерден баштайлы жана төмөнкү мүмкүнчүлүктөрү бар тиркеме менен аяктайлы:

- HTTPS үчүн Let's Encrypt колдонуу.
— API роутер катары иштөө.
— Орточо программа менен иштөө.
— Статикалык файлдарды иштетүү.
— Туура өчүрүү.

Skillbox сунуштайт: Практикалык курс "Нөлдөн баштап Python иштеп чыгуучусу".

Биз эсиңизге салабыз: "Хабрдын" бардык окурмандары үчүн - "Habr" промо-кодун колдонуу менен каалаган Skillbox курсуна катталганда 10 000 рубль арзандатуу.

Салам дүйнө!

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

Андан кийин, сиз колдонмону иштетип, баракты ачсаңыз көрүү .xrf, анда сиз дароо "Салам, дүйнө!" текстин көрөсүз. (бардыгы туура иштесе, албетте).

Биз иштеткичти кийинчерээк бир нече жолу колдонобуз, бирок адегенде баары кантип иштээрин түшүнүп алалы.

net/http

Мисал пакетти колдонгон net/http, ал серверлерди жана HTTP кардарларын өнүктүрүү үчүн Go'догу негизги курал болуп саналат. Кодду түшүнүү үчүн үч маанилүү элементтин маанисин түшүнөлү: http.Handler, http.ServeMux жана http.Server.

HTTP иштеткичтери

Биз суроо-талапты алганда, иштетүүчү аны талдап, жооп берет. Go'до иштеткичтер төмөнкүдөй ишке ашырылат:

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

Биринчи мисал http.HandleFunc жардамчы функциясын колдонот. Ал башка функцияны ороп алат, ал өз кезегинде http.ResponseWriter жана http.Requestти ServeHTTPге алат.

Башкача айтканда, Голангдагы иштеткичтер бир интерфейсте берилген, бул программистке көптөгөн мүмкүнчүлүктөрдү берет. Ошентип, мисалы, орто программа иштеткичтин жардамы менен ишке ашырылат, мында ServeHTTP адегенде бир нерсе жасап, андан кийин башка иштетүүчүнүн ServeHTTP ыкмасын чакырат.

Жогоруда айтылгандай, иштетүүчүлөр жөн гана суроо-талаптарга жоопторду жаратышат. Бирок кайсы бир иштеткич белгилүү бир убакта колдонулушу керек?

Маршруттук суроо

Туура тандоо үчүн, HTTP мультиплексерин колдонуңуз. Бир катар китепканаларда ал мухер же роутер деп аталат, бирок алардын баары бирдей. Мультиплексордун милдети суроо-талап жолун талдоо жана тиешелүү иштеткичти тандоо.

Эгер сизге татаал багыттоо үчүн колдоо керек болсо, анда үчүнчү тараптын китепканаларын колдонуу жакшы. Кээ бир эң алдыңкылары - горилла/мукс и go-chi/chi, бул китепканалар аралык иштетүүнү эч кандай көйгөйсүз ишке ашырууга мүмкүндүк берет. Алардын жардамы менен сиз коймо белгинин маршрутун конфигурациялай аласыз жана бир катар башка тапшырмаларды аткара аласыз. Алардын артыкчылыгы стандарттык HTTP иштетүүчүлөр менен шайкеш келет. Натыйжада, сиз келечекте өзгөртө турган жөнөкөй кодду жаза аласыз.

Кадимки кырдаалда татаал алкактар ​​менен иштөө стандарттуу эмес чечимдерди талап кылат жана бул демейки иштеткичтерди колдонууну кыйла татаалдантат. Колдонмолордун басымдуу көпчүлүгүн түзүү үчүн демейки китепкана менен жөнөкөй роутердин айкалышы жетиштүү болот.

Суроолорду иштетүү

Мындан тышкары, бизге кирүүчү байланыштарды "угуу" жана бардык суроо-талаптарды туура иштетүүчүгө багыттай турган компонент керек. http.Server бул тапшырманы оңой эле чече алат.

Төмөндө сервер байланышты иштетүүгө байланышкан бардык тапшырмалар үчүн жооптуу экенин көрсөтүп турат. Бул, мисалы, TLS протоколун колдонуу менен иштейт. http.ListenAndServer чалуусун ишке ашыруу үчүн стандарттуу HTTP сервери колдонулат.

Эми татаалыраак мисалдарды карап көрөлү.

Let's Encrypt кошуу

Демейки боюнча, биздин колдонмо HTTP протоколу аркылуу иштейт, бирок HTTPS протоколун колдонуу сунушталат. Бул Go менен көйгөйсүз кылса болот. Эгер сиз күбөлүк жана купуя ачкыч алган болсоңуз, анда туура сертификат жана негизги файлдар менен ListenAndServeTLSти каттоо жетиштүү.

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

Сиз ар дайым жакшыраак кыла аласыз.

Кел код автоматтык узартуу менен акысыз сертификаттарды берет. Кызматты колдонуу үчүн сизге пакет керек autocert.

Аны конфигурациялоонун эң оңой жолу - http.Serve менен бирге autocert.NewListener ыкмасын колдонуу. Бул ыкма 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 колдоосун ишке ашыруунун оңой жолу.

Ыңгайлаштырылган маршруттарды кошуу

Стандарттык китепканага киргизилген демейки роутер жакшы, бирок бул абдан жөнөкөй. Көпчүлүк тиркемелер татаалыраак маршрутту талап кылат, анын ичинде уяланган жана коймочтуу маршруттар, же жол үлгүлөрүн жана параметрлерин орнотуу процедурасы.

Бул учурда ал пакеттерди колдонууга арзырлык горилла/мукс и go-chi/chi. Биз акыркы менен кантип иштөөнү үйрөнөбүз - мисал төмөндө көрсөтүлгөн.

Биздин API үчүн маршруттарды камтыган api/v1/api.go файлы берилген:

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

Үчүнчү тараптын роутерлери бар, мисалы, чи сыяктуу, алар орто программанын функцияларын кеңейтүүгө мүмкүндүк берет.

Статикалык файлдар менен иштөө

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 сунуштайт:

Source: www.habr.com

Комментарий кошуу