Web server kev loj hlob hauv Golang - los ntawm yooj yim mus rau complex

Web server kev loj hlob hauv Golang - los ntawm yooj yim mus rau complex

Tsib xyoos dhau los kuv pib txhim kho Gophish, qhov no muab lub sijhawm los kawm Golang. Kuv pom tau tias Go yog ib hom lus muaj zog, ua tiav los ntawm ntau lub tsev qiv ntawv. Mus yog ntau yam: tshwj xeeb, nws tuaj yeem siv los tsim cov ntawv thov sab server yam tsis muaj teeb meem.

Kab lus no yog hais txog kev sau cov server hauv Go. Cia peb pib nrog tej yam yooj yim xws li "Nyob zoo ntiaj teb!" thiab xaus nrog daim ntawv thov nrog cov peev txheej hauv qab no:

- Siv Let's Encrypt rau HTTPS.
- Ua haujlwm raws li API router.
- Ua haujlwm nrog cov khoom nruab nrab.
- Ua cov ntaub ntawv zoo li qub.
-Qhov raug kaw.

Skillbox pom zoo: Cov chav kawm siv tau "Python developer los ntawm kos".

Peb nco qab: rau txhua tus neeg nyeem Habr - 10 ruble luv nqi thaum tso npe rau hauv ib chav kawm Skillbox siv Habr promo code.

Nyob zoo, ntiaj teb!

Koj tuaj yeem tsim lub web server hauv Go sai heev. Ntawm no yog ib qho piv txwv ntawm kev siv tus handler uas rov qab "Nyob zoo, ntiaj teb!" tau cog lus saum toj no.

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

Tom qab no, yog tias koj khiav daim ntawv thov thiab qhib nplooj ntawv localhost, ces koj yuav pom cov ntawv tam sim ntawd "Nyob zoo, ntiaj teb!" (yog tias txhua yam ua haujlwm raug, tau kawg).

Peb mam li siv tus tuav ntau zaus tom qab, tab sis ua ntej cia peb nkag siab tias txhua yam ua haujlwm li cas.

net/http

Qhov piv txwv siv lub pob net/http, nws yog qhov cuab yeej tseem ceeb hauv Go rau kev txhim kho ob lub servers thiab HTTP cov neeg siv khoom. Txhawm rau nkag siab cov cai, cia peb nkag siab lub ntsiab lus ntawm peb lub ntsiab lus tseem ceeb: http.Handler, http.ServeMux thiab http.Server.

HTTP handlers

Thaum peb tau txais kev thov, tus neeg tuav ntaub ntawv txheeb xyuas nws thiab tsim cov lus teb. Handlers hauv Go yog siv raws li hauv qab no:

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

Thawj qhov piv txwv siv http.HandleFunc tus pab ua haujlwm. Nws qhwv lwm txoj haujlwm, uas nyob rau hauv lem yuav siv http.ResponseWriter thiab http.Request rau hauv ServeHTTP.

Hauv lwm lo lus, cov neeg ua haujlwm hauv Golang tau nthuav tawm hauv ib qho interface, uas muab ntau txoj hauv kev rau tus programmer. Yog li, piv txwv li, cov khoom nruab nrab yog siv los ntawm tus tuav, qhov twg ServeHTTP ua ntej ua ib yam dab tsi thiab tom qab ntawd hu rau ServeHTTP txoj kev ntawm lwm tus tuav.

Raws li tau hais los saum no, cov neeg ua haujlwm tsuas yog tsim cov lus teb rau cov lus thov. Tab sis dab tsi tshwj xeeb handler yuav tsum tau siv nyob rau hauv ib lub sij hawm?

Thov Routing

Txhawm rau xaiv qhov yog, siv HTTP multiplexer. Hauv ntau lub tsev qiv ntawv nws yog hu ua muxer lossis router, tab sis lawv txhua tus yog tib yam. Lub luag haujlwm ntawm multiplexer yog txhawm rau txheeb xyuas txoj kev thov thiab xaiv tus neeg tuav haujlwm tsim nyog.

Yog tias koj xav tau kev txhawb nqa rau txoj kev ua haujlwm nyuaj, ces nws yog qhov zoo dua los siv cov tsev qiv ntawv thib peb. Qee qhov kev tshaj lij tshaj plaws - gorilla/mus ΠΈ mus-chi/chi, cov tsev qiv ntawv no ua rau nws muaj peev xwm los siv kev ua haujlwm nruab nrab yam tsis muaj teeb meem. Nrog rau lawv cov kev pab, koj tuaj yeem teeb tsa cov kab ntawv qub thiab ua ntau yam haujlwm. Lawv qhov zoo dua yog kev sib raug zoo nrog tus qauv HTTP handlers. Yog li ntawd, koj tuaj yeem sau cov lej yooj yim uas tuaj yeem hloov kho yav tom ntej.

Ua haujlwm nrog cov txheej txheem nyuaj hauv qhov xwm txheej ib txwm yuav xav tau cov kev daws teeb meem tsis zoo, thiab qhov no cuam tshuam rau kev siv cov neeg ua haujlwm tsis raug. Txhawm rau tsim cov ntawv thov feem ntau, kev sib xyaw ua ke ntawm lub tsev qiv ntawv qub thiab lub router yooj yim yuav txaus.

Kev ua lus nug

Tsis tas li ntawd, peb xav tau ib qho kev tivthaiv uas yuav "mloog" rau kev sib txuas lus thiab xa rov qab txhua qhov kev thov mus rau tus neeg ua haujlwm raug. http.Server tuaj yeem ua haujlwm tau yooj yim.

Cov hauv qab no qhia tau hais tias tus neeg rau zaub mov yog lub luag haujlwm rau txhua txoj haujlwm uas cuam tshuam nrog kev sib txuas ua haujlwm. Qhov no, piv txwv li, ua haujlwm siv TLS raws tu qauv. Txhawm rau siv http.ListenAndServer hu, tus qauv HTTP server yog siv.

Tam sim no cia peb saib ntau cov piv txwv nyuaj.

Ntxiv Let's Encrypt

Los ntawm lub neej ntawd, peb daim ntawv thov khiav dhau HTTP raws tu qauv, tab sis nws raug pom zoo kom siv HTTPS raws tu qauv. Qhov no tuaj yeem ua tiav yam tsis muaj teeb meem hauv Go. Yog tias koj tau txais daim ntawv pov thawj thiab tus yuam sij ntiag tug, ces nws txaus los sau npe ListenAndServeTLS nrog daim ntawv pov thawj tseeb thiab cov ntaub ntawv tseem ceeb.

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

Koj tuaj yeem ua tau zoo dua.

Cia Peb Los Ntseeg muab daim ntawv pov thawj pub dawb nrog kev rov ua dua tshiab tsis siv neeg. Txhawm rau siv qhov kev pabcuam, koj xav tau ib pob autocert.

Txoj kev yooj yim tshaj plaws los teeb tsa nws yog siv autocert.NewListener txoj kev ua ke nrog http.Serve. Tus txheej txheem tso cai rau koj kom tau txais thiab hloov kho TLS daim ntawv pov thawj thaum HTTP server txheej txheem thov:

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

Yog tias peb qhib qhov browser piv txwv, peb yuav tau txais HTTPS teb "Nyob zoo, ntiaj teb!"

Yog tias koj xav tau kev teeb tsa kom ntxaws ntxiv, ces koj yuav tsum siv autocert.Manager tus thawj tswj. Tom qab ntawd peb tsim peb tus kheej http.Server piv txwv (txog tam sim no peb siv nws los ntawm lub neej ntawd) thiab ntxiv tus thawj tswj rau 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("", "")

Qhov no yog ib txoj hauv kev yooj yim los siv tag nrho HTTPS kev txhawb nqa nrog kev rov ua dua daim ntawv pov thawj tsis siv neeg.

Ntxiv cov kev cai

Lub neej ntawd router suav nrog hauv cov tsev qiv ntawv tus qauv yog qhov zoo, tab sis nws yog qhov yooj yim heev. Cov ntawv thov feem ntau xav tau txoj hauv kev nyuaj dua, suav nrog txoj hauv kev nested thiab wildcard, lossis cov txheej txheem rau kev teeb tsa cov qauv thiab cov kev txwv.

Hauv qhov no nws tsim nyog siv pob khoom gorilla/mus ΠΈ mus-chi/chi. Peb yuav kawm yuav ua li cas ua hauj lwm nrog tom kawg - ib qho piv txwv yog qhia hauv qab no.

Muab yog cov ntaub ntawv api/v1/api.go uas muaj txoj hauv kev rau peb 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
}

Peb teeb tsa api/vq ua ntej rau txoj hauv kev hauv cov ntaub ntawv tseem ceeb.

Peb tuaj yeem txuas qhov no rau peb lub router tseem ceeb hauv qab api / v1 / prefix rov qab rau hauv peb daim ntawv thov tseem ceeb:

// 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 qhov yooj yim ntawm kev ua hauj lwm nrog txoj kev nyuaj ua rau nws ua tau kom yooj yim rau kev txhim kho thiab kev saib xyuas ntawm cov ntaub ntawv loj, complex.

Ua haujlwm nrog cov khoom nruab nrab

Staging suav nrog wrapping ib tus HTTP handler nrog lwm tus, ua kom nws ua tau sai ua qhov tseeb, compression, txiav, thiab ntau lwm yam haujlwm.

Ua piv txwv, cia peb saib ntawm http.Handler interface; peb yuav siv nws los sau tus tuav ntaub ntawv uas txheeb xyuas cov neeg siv kev pabcuam.

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

Muaj cov neeg sab nrauv routers, xws li chi, uas tso cai rau koj mus txuas ntxiv kev ua haujlwm nruab nrab.

Ua haujlwm nrog cov ntaub ntawv zoo li qub

Lub tsev qiv ntawv Go tus qauv muaj peev xwm ua haujlwm nrog cov ntsiab lus zoo li qub, suav nrog cov duab, JavaScript thiab CSS cov ntaub ntawv. Lawv tuaj yeem nkag tau los ntawm http.FileServer muaj nuj nqi. Nws xa rov qab tus neeg tuav haujlwm uas ua haujlwm rau cov ntaub ntawv los ntawm cov npe tshwj xeeb.

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

Nws yog qhov tsim nyog nco ntsoov tias http.Dir qhia cov ntsiab lus ntawm cov npe yog tias nws tsis muaj cov ntaub ntawv tseem ceeb index.html. Hauv qhov no, txhawm rau tiv thaiv cov npe ntawm kev cuam tshuam, koj yuav tsum siv lub pob unindexed.

Qhov raug kaw

Mus kuj muaj qhov tshwj xeeb hu ua kev kaw zoo ntawm HTTP server. Qhov no tuaj yeem ua tiav siv txoj kev Shutdown() . Cov neeg rau zaub mov pib hauv goroutine, thiab tom qab ntawd cov channel tau mloog kom tau txais cov teeb liab cuam tshuam. Thaum lub teeb liab tau txais, lub server kaw, tab sis tsis tam sim ntawd, tab sis tom qab ob peb feeb.

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)

Raws li qhov xaus

Mus yog hom lus muaj zog nrog lub tsev qiv ntawv yuav luag thoob ntiaj teb. Nws lub peev xwm ua haujlwm tau dav heev, thiab lawv tuaj yeem txhim kho siv cov kev sib tshuam - qhov no tso cai rau koj los tsim cov HTTP servers ntseeg tau tiag tiag.

Skillbox pom zoo:

Tau qhov twg los: www.hab.com

Ntxiv ib saib