Голанг дахь вэб серверүүдийг хөгжүүлэх - энгийнээс нарийн төвөгтэй хүртэл

Голанг дахь вэб серверүүдийг хөгжүүлэх - энгийнээс нарийн төвөгтэй хүртэл

Таван жилийн өмнө би эхэлсэн Gophish хөгжүүлэх, энэ нь Голанг сурах боломжтой болсон. Go хэл бол олон номын сангуудаар дүүрэн хүчирхэг хэл гэдгийг би ойлгосон. Go нь олон талт байдаг: ялангуяа та үүнтэй сервер талын програмуудыг хялбархан хөгжүүлэх боломжтой.

Энэ нийтлэл нь Go дээр сервер бичих тухай юм. "Сайн уу ертөнц!" гэх мэт энгийн зүйлсээс эхэлж, дараах функцуудтай программыг дуусгацгаая.

- Let's Encrypt-ийг HTTPS-д ашиглах.
- API чиглүүлэгчээр ажиллах.
- Дунд програм хангамжтай ажиллах.
- Статик файлуудтай ажиллах.
- Зөв унтрах.

Skillbox зөвлөж байна: Практик курс "Эхнээс нь Python хөгжүүлэгч".

Бид танд сануулж байна: "Хабр" -ын бүх уншигчдад - "Habr" сурталчилгааны кодыг ашиглан Skillbox-ын аль ч курст бүртгүүлэхдээ 10 рублийн хөнгөлөлт.

Сайн байна уу ертөнц!

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

Үүний дараа, хэрэв та програмыг ажиллуулж, хуудсыг нээнэ үү тестлээрэй, тэгвэл та тэр даруй "Сайн уу, дэлхий!" (Мэдээжийн хэрэг, хэрэв бүх зүйл зөв ажиллаж байвал).

Дараах зүйлд бид зохицуулагчийг дахин дахин ашиглах болно, гэхдээ эхлээд энэ бүхэн хэрхэн ажилладагийг ойлгоцгооё.

net/http

Жишээ нь багцыг ашигласан net/http, сервер болон HTTP клиентүүдийг хоёуланг нь хөгжүүлэх Go-ийн үндсэн хэрэгсэл юм. Кодыг ойлгохын тулд http.Handler, http.ServeMux, http.Server гэсэн гурван чухал элементийн утгыг ойлгоцгооё.

HTTP зохицуулагчид

Бид хүсэлтийг хүлээн авах үед зохицуулагч үүнийг задлан шинжилж, хариу гаргадаг. Go дахь зохицуулагчийг дараах байдлаар хэрэгжүүлдэг.

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

Эхний жишээнд http.HandleFunc туслах функцийг ашигладаг. Энэ нь ServeHTTP дахь http.ResponseWriter болон http.Request-ийг хүлээн авах өөр функцийг боож өгдөг.

Өөрөөр хэлбэл, Голанг дахь боловсруулагчдыг нэг интерфейсээр төлөөлдөг бөгөөд энэ нь програмистуудад маш их боломжийг олгодог. Жишээлбэл, дунд програм хангамжийг зохицуулагч ашиглан хэрэгжүүлдэг бөгөөд ServeHTTP эхлээд ямар нэгэн зүйл хийж, дараа нь өөр зохицуулагчийн ServeHTTP аргыг дууддаг.

Дээр дурьдсанчлан, зохицуулагчид хүсэлтийн хариуг л гаргадаг. Гэхдээ аль зохицуулагчийг тодорхой цагт ашиглах ёстой вэ?

Чиглүүлэлт хүсэх

Зөв сонголт хийхийн тулд HTTP multiplexer ашиглана уу. Хэд хэдэн номын санд үүнийг muxer эсвэл чиглүүлэгч гэж нэрлэдэг боловч бүгд адилхан. Мультиплексорын үүрэг нь хүсэлтийн замд дүн шинжилгээ хийж, тохирох зохицуулагчийг сонгох явдал юм.

Хэрэв танд нарийн төвөгтэй чиглүүлэлтийн дэмжлэг хэрэгтэй бол гуравдагч талын номын санг ашиглах нь дээр. Хамгийн дэвшилтэт зүйлсийн нэг горилла/мукс и го-чи/чи, эдгээр сангууд нь завсрын боловсруулалтыг ямар ч асуудалгүйгээр хэрэгжүүлэх боломжтой болгодог. Тэдгээрийн тусламжтайгаар та орлуулагдах тэмдэгт чиглүүлэлт хийж, бусад хэд хэдэн ажлыг гүйцэтгэх боломжтой. Тэдний давуу тал нь стандарт HTTP зохицуулагчтай нийцтэй байх явдал юм. Үүний үр дүнд та ирээдүйд өөрчлөх боломжтой энгийн код бичиж болно.

Ердийн нөхцөлд нарийн төвөгтэй хүрээтэй ажиллахад тийм ч стандарт бус шийдлүүд шаардагдах бөгөөд энэ нь анхдагч зохицуулагчийг ашиглахад ихээхэн хүндрэл учруулдаг. Анхдагч номын сан болон энгийн чиглүүлэгчийн хослол нь ихэнх програмуудыг үүсгэхэд хангалттай.

Асуулга боловсруулах

Нэмж дурдахад бидэнд ирж буй холболтыг "сонсож" бүх хүсэлтийг зөв зохицуулагч руу чиглүүлэх бүрэлдэхүүн хэсэг хэрэгтэй. http.Server энэ ажлыг амархан даван туулж чадна.

Дараах нь сервер нь холболттой холбоотой бүх ажлыг хариуцдаг болохыг харуулж байна. Жишээлбэл, энэ нь TLS протокол дээр ажилладаг. Стандарт HTTP серверийг http.ListenAndServer дуудлагыг хэрэгжүүлэхэд ашигладаг.

Одоо илүү төвөгтэй жишээнүүдийг харцгаая.

Шифрлэцгээе

Анхдагч байдлаар, манай програм HTTP протокол дээр ажилладаг боловч HTTPS протоколыг ашиглахыг зөвлөж байна. Go-д үүнийг асуудалгүйгээр хийх боломжтой. Хэрэв та гэрчилгээ болон хувийн түлхүүр хүлээн авсан бол ListenAndServeTLS-ийг зөв гэрчилгээ, түлхүүр файлаар бичихэд хангалттай.

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

Та үргэлж илүү сайн хийж чадна.

Шифрийг нь хийцгээе автоматаар сунгах боломжтой гэрчилгээг үнэ төлбөргүй өгдөг. Үйлчилгээг ашиглахын тулд танд багц хэрэгтэй autocert.

Үүнийг тохируулах хамгийн хялбар арга бол autocert.NewListener аргыг http.Serve-тэй хослуулан ашиглах явдал юм. Энэхүү арга нь HTTP сервер хүсэлтийг боловсруулах үед TLS гэрчилгээг хүлээн авах, шинэчлэх боломжийг танд олгоно.

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-д зориулсан маршрутуудыг агуулсан 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

Хэрэв үндсэн index.html файл агуулаагүй бол http.Dir нь директорийн агуулгыг харуулдаг гэдгийг санаарай. Энэ тохиолдолд лавлахыг эвдэхээс урьдчилан сэргийлэхийн тулд багцыг ашиглах хэрэгтэй unindexed.

Зөв унтрах

Go нь HTTP серверийг хаах зэрэг функцтэй. Үүнийг Shutdown() аргыг ашиглан хийж болно. Серверийг goroutine горимд эхлүүлж, дараа нь тасалдлын дохиог хүлээн авахын тулд сувгийг сонсдог. Дохио хүлээн авмагц сервер унтардаг, гэхдээ тэр даруй биш, хэдхэн секундын дараа.

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

сэтгэгдэл нэмэх