Pagpalambo sa mga web server sa Golang - gikan sa yano hangtod sa komplikado

Pagpalambo sa mga web server sa Golang - gikan sa yano hangtod sa komplikado

Lima ka tuig ang milabay nagsugod ko pagpalambo sa Gophish, kini nahimong posible nga makat-on sa Golang. Nakaamgo ko nga ang Go usa ka gamhanan nga pinulongan, nga gisuportahan sa daghang mga librarya. Daghag gamit ang Go: sa partikular, dali ka makapalambo sa mga aplikasyon sa kilid sa server uban niini.

Kini nga artikulo bahin sa pagsulat sa usa ka server sa Go. Magsugod ta sa yano nga mga butang sama sa "Hello world!" ug matapos sa usa ka aplikasyon nga adunay kini nga mga bahin:

- Paggamit sa Let's Encrypt para sa HTTPS.
- Pagtrabaho isip usa ka API router.
- Pagtrabaho uban sa middleware.
- Pagdumala sa mga static nga file.
- Husto nga pagsira.

Girekomenda sa Skillbox: Praktikal nga kurso "Python developer gikan sa scratch".

Gipahinumduman namon ikaw: alang sa tanan nga mga magbabasa sa "Habr" - usa ka diskwento sa 10 nga mga rubles kung nagpalista sa bisan unsang kurso sa Skillbox gamit ang code sa promosyon nga "Habr".

Kumusta, kalibutan!

Ang paghimo og web server sa Go mahimong paspas kaayo. Ania ang usa ka pananglitan sa paggamit sa usa ka handler nga nagbalik sa "Hello, world!" nga gisaad sa ibabaw.

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

Pagkahuman niana, kung gipadagan nimo ang aplikasyon ug ablihan ang panid localhost, unya makita dayon nimo ang teksto nga "Hello, world!" (siyempre, kung ang tanan molihok sa husto).

Atong gamiton ang handler nga balik-balik sa mosunod, apan una natong sabton kung giunsa kini tanan.

net/http

Ang pananglitan naggamit sa pakete net/http, mao ang nag-unang himan sa Go alang sa pagpalambo sa mga server ug HTTP nga mga kliyente. Aron masabtan ang code, atong sabton ang kahulogan sa tulo ka importanteng elemento: http.Handler, http.ServeMux ug http.Server.

Mga tigdumala sa HTTP

Kung makadawat kami usa ka hangyo, gi-parse kini sa handler ug maghimo usa ka tubag. Ang mga Handler sa Go gipatuman sama sa mosunod:

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

Ang unang pananglitan naggamit sa http.HandleFunc helper function. Giputos niini ang laing function nga sa baylo modawat sa http.ResponseWriter ug http.Request sa ServeHTTP.

Sa laing pagkasulti, ang mga tigdumala sa Golang girepresentahan sa usa ka interface, nga naghatag daghang mga oportunidad alang sa programmer. Busa, pananglitan, ang middleware gipatuman gamit ang usa ka handler, diin ang ServeHTTP una nga naghimo ug usa ka butang ug dayon nagtawag sa ServeHTTP nga pamaagi sa laing handler.

Sama sa gihisgutan sa ibabaw, ang mga tigdumala nagporma lang og mga tubag sa mga hangyo. Apan unsa nga handler ang angay gamiton sa usa ka partikular nga oras?

Paghangyo sa Routing

Aron makahimo sa husto nga pagpili, gamita ang HTTP multiplexer. Sa ubay-ubay nga mga librarya kini gitawag nga muxer o router, apan silang tanan managsama. Ang gimbuhaton sa multiplexer mao ang pag-analisar sa agianan sa paghangyo ug pagpili sa angay nga handler.

Kung kinahanglan nimo ang suporta alang sa komplikado nga ruta, nan mas maayo nga gamiton ang mga librarya sa ikatulo nga partido. Usa sa labing abante gorilya/mux и go-chi/chi, kini nga mga librarya nagpaposible sa pagpatuman sa intermediate nga pagproseso nga walay mga problema. Sa ilang tabang, mahimo nimong i-set up ang wildcard routing ug mahimo ang daghang uban pang mga buluhaton. Ang ilang bentaha mao ang pagkaangay sa mga standard nga tigdumala sa HTTP. Ingon usa ka sangputanan, mahimo nimong isulat ang yano nga code nga mahimong usbon sa umaabot.

Ang pagtrabaho kauban ang mga komplikado nga mga balangkas sa usa ka normal nga kahimtang nanginahanglan dili kaayo sagad nga mga solusyon, ug kini labi ka komplikado sa paggamit sa mga default nga tigdumala. Ang kombinasyon sa default library ug usa ka yano nga router igo na sa paghimo sa kadaghanan sa mga aplikasyon.

Pagproseso sa Pangutana

Dugang pa, kinahanglan namon ang usa ka sangkap nga "maminaw" alang sa umaabot nga mga koneksyon ug i-redirect ang tanan nga mga hangyo sa husto nga tigdumala. Ang http.Server dali nga makasagubang niini nga buluhaton.

Ang mosunod nagpakita nga ang server maoy responsable sa tanang buluhaton nga may kalabotan sa pagdumala sa mga koneksyon. Kini, pananglitan, nagtrabaho sa TLS protocol. Usa ka standard nga HTTP server ang gigamit sa pagpatuman sa http.ListenAndServer nga tawag.

Karon atong tan-awon ang mas komplikado nga mga pananglitan.

Pagdugang Let's Encrypt

Sa default, ang among aplikasyon nagdagan sa HTTP protocol, apan girekomenda nga gamiton ang HTTPS protocol. Sa Go, mahimo kini nga walay mga problema. Kung nakadawat ka usa ka sertipiko ug usa ka pribado nga yawe, nan igo na ang pagsulat sa ListenAndServeTLS nga adunay husto nga sertipiko ug yawe nga mga file.

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

Mahimo nimo kanunay nga mas maayo.

Atong Sulatan naghatag libre nga mga sertipiko nga adunay posibilidad nga awtomatiko nga pagbag-o. Aron magamit ang serbisyo, kinahanglan nimo ang usa ka pakete autocert.

Ang pinakasayon ​​nga paagi sa pag-set up niini mao ang paggamit sa autocert.NewListener nga pamaagi inubanan sa http.Serve. Gitugotan ka sa pamaagi nga makadawat ug magbag-o sa mga sertipiko sa TLS samtang giproseso sa HTTP server ang mga hangyo:

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

Kung atong ablihan sa browser example.com, nakakuha kami usa ka tubag sa HTTPS nga "Hello, kalibutan!".

Kung kinahanglan nimo ang mas detalyado nga configuration, nan kinahanglan nimo nga gamiton ang autocert.Manager. Dayon naghimo kami sa among kaugalingong http.Server nga pananglitan (sa pagkakaron gigamit na namo kini pinaagi sa default) ug idugang ang manedyer sa TLSConfig server:

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

Kini usa ka dali nga paagi sa pagpatuman sa hingpit nga suporta sa HTTPS nga adunay awtomatikong pagbag-o sa sertipiko.

Pagdugang Custom nga mga Ruta

Ang default nga router nga gilakip sa standard nga librarya nindot, apan sukaranan kaayo. Kadaghanan sa mga aplikasyon nanginahanglan ug labi ka komplikado nga pag-ruta, lakip ang mga nested ug wildcard nga mga ruta, o ang pamaagi sa pag-set sa mga pattern ug parameter sa agianan.

Sa kini nga kaso, kinahanglan nimo nga gamiton ang mga pakete gorilya/mux и go-chi/chi. Kita makakat-on kon sa unsang paagi sa pagtrabaho uban sa ulahi - ang usa ka pananglitan gipakita sa ubos.

Ang gihatag mao ang api/v1/api.go nga file nga adunay mga ruta para sa among 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
}

Among gibutang ang api/vq prefix para sa mga rota sa main file.

Mahimo namong i-mount kini sa among main router ubos sa api/v1/ prefix balik sa among main application:

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

Ang kasayon ​​sa pagtrabaho sa komplikado nga mga ruta sa Go nagpaposible sa pagpayano sa pag-istruktura ug pagmentinar sa dagkong komplikadong mga aplikasyon.

Nagtrabaho sa middleware

Sa kaso sa intermediate nga pagproseso, ang pagputos sa usa ka HTTP handler sa lain gigamit, nga nagpaposible sa dali nga pagpahigayon sa authentication, compression, logging, ug uban pang mga function.

Isip usa ka pananglitan, atong tagdon ang http.Handler interface, uban sa tabang niini kita magsulat sa usa ka handler nga adunay authentication sa mga tiggamit sa serbisyo.

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

Adunay mga third-party nga mga router, sama sa chi, nga nagtugot kanimo sa pagpalapad sa pagpaandar sa intermediate nga pagproseso.

Pagtrabaho uban ang static nga mga file

Ang standard library ni Go naglakip sa mga pasilidad alang sa pagtrabaho uban sa static nga sulod, lakip ang mga hulagway, ingon man ang JavaScript ug CSS nga mga file. Mahimo silang ma-access pinaagi sa http.FileServer function. Nagbalik kini sa usa ka handler nga nag-apod-apod sa mga file gikan sa usa ka piho nga direktoryo.

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

Siguruha nga hinumdoman nga ang http.Dir nagpakita sa mga sulud sa direktoryo kung wala kini sulud sa panguna nga index.html file. Sa kini nga kaso, aron mapugngan ang direktoryo nga makompromiso, kinahanglan nimo nga gamiton ang package unindexed.

Husto nga pagsira

Ang Go usab adunay usa ka bahin sama sa usa ka madanihon nga pagsira sa HTTP server. Mahimo kini gamit ang Shutdown() nga pamaagi. Ang server gisugdan sa usa ka goroutine, ug dayon ang channel paminawon aron makadawat og interrupt signal. Sa diha nga ang signal madawat, ang server mapalong, apan dili dayon, apan human sa pipila ka segundo.

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)

Isip usa ka konklusyon

Ang Go usa ka gamhanan nga pinulongan nga adunay halos unibersal nga standard library. Ang mga default nga kapabilidad niini lapad kaayo, ug mahimo nimo kining palig-onon sa tabang sa mga interface - kini nagtugot kanimo sa pagpalambo sa tinuod nga kasaligan nga mga HTTP server.

Girekomenda sa Skillbox:

Source: www.habr.com

Idugang sa usa ka comment