Հինգ տարի առաջ ես սկսեցի զարգացնել Gophish, սա հնարավորություն տվեց սովորել Գոլանգը։ Ես հասկացա, որ Go-ն հզոր լեզու է, որը լրացվում է բազմաթիվ գրադարաններով: Go-ն բազմակողմանի է. մասնավորապես, այն կարող է օգտագործվել առանց որևէ խնդրի սերվերային հավելվածներ մշակելու համար:
Այս հոդվածը Go-ում սերվեր գրելու մասին է: Սկսենք պարզ բաներից, ինչպիսիք են «Բարև աշխարհ!» և ավարտենք հետևյալ հնարավորություններով հավելվածով.
- Օգտագործելով Let's Encrypt-ը HTTPS-ի համար:
— Աշխատում է որպես API երթուղիչ:
- Աշխատեք միջին ծրագրաշարի հետ:
- Ստատիկ ֆայլերի մշակում:
- Ճիշտ անջատում:
Դրանից հետո, եթե գործարկեք հավելվածը և բացեք էջը localhost, ապա անմիջապես կտեսնեք «Բարև, աշխարհ» տեքստը: (եթե ամեն ինչ ճիշտ է աշխատում, իհարկե):
Ավելի ուշ մենք կօգտագործենք մշակիչը մի քանի անգամ, բայց նախ եկեք հասկանանք, թե ինչպես է ամեն ինչ աշխատում:
ցանց/http
Օրինակը օգտագործեց փաթեթը net/http, այն Go-ի առաջնային գործիքն է ինչպես սերվերների, այնպես էլ HTTP հաճախորդների մշակման համար: Կոդը հասկանալու համար եկեք հասկանանք երեք կարևոր տարրերի նշանակությունը՝ http.Handler, http.ServeMux և http.Server:
HTTP մշակիչներ
Երբ մենք հարցում ենք ստանում, մշակողը վերլուծում է այն և առաջացնում պատասխան: Handlers in Go-ն իրականացվում են հետևյալ կերպ.
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
Առաջին օրինակը օգտագործում է http.HandleFunc օգնական ֆունկցիան։ Այն փաթաթում է մեկ այլ գործառույթ, որն իր հերթին http.ResponseWriter-ը և http.Request-ը տեղափոխում է ServeHTTP:
Այսինքն, Golang-ում մշակողները ներկայացված են մեկ ինտերֆեյսով, որը ծրագրավորողին տալիս է բազմաթիվ տարբերակներ։ Այսպիսով, օրինակ, միջին ծրագիրը իրականացվում է մշակողի միջոցով, որտեղ ServeHTTP նախ ինչ-որ բան է անում, այնուհետև կանչում է մեկ այլ մշակողի ServeHTTP մեթոդը:
Ինչպես նշվեց վերևում, մշակողները պարզապես առաջացնում են հարցումների պատասխաններ: Բայց կոնկրետ ո՞ր կարգավորիչը պետք է օգտագործվի որոշակի ժամանակահատվածում:
Հարցրեք երթուղի
Ճիշտ ընտրություն կատարելու համար օգտագործեք HTTP մուլտիպլեքսոր: Մի շարք գրադարաններում այն կոչվում է muxer կամ router, բայց դրանք բոլորը նույնն են: Multiplexer-ի գործառույթն է վերլուծել հարցումների ուղին և ընտրել համապատասխան մշակողը:
Եթե Ձեզ անհրաժեշտ է աջակցություն բարդ երթուղիների համար, ապա ավելի լավ է օգտագործել երրորդ կողմի գրադարանները: Որոշ առավել առաջադեմ - գորիլա/մաքս и go-chi/chi, այս գրադարանները հնարավորություն են տալիս առանց խնդիրների իրականացնել միջանկյալ մշակում։ Նրանց օգնությամբ դուք կարող եք կարգավորել wildcard routing-ը և կատարել մի շարք այլ առաջադրանքներ: Նրանց առավելությունը ստանդարտ HTTP մշակողների հետ համատեղելիությունն է: Արդյունքում կարող եք գրել պարզ կոդ, որը կարող է փոփոխվել ապագայում։
Նորմալ իրավիճակում բարդ շրջանակների հետ աշխատելը կպահանջի ոչ ստանդարտ լուծումներ, և դա զգալիորեն բարդացնում է լռելյայն մշակողների օգտագործումը: Հավելվածների ճնշող մեծամասնությունը ստեղծելու համար բավական կլինի լռելյայն գրադարանի և պարզ երթուղիչի համադրությունը:
Հարցման մշակում
Բացի այդ, մեզ անհրաժեշտ է բաղադրիչ, որը «կլսի» մուտքային կապերի համար և վերահղելու բոլոր հարցումները ճիշտ մշակողին: http.Server-ը կարող է հեշտությամբ կարգավորել այս խնդիրը:
Հետևյալը ցույց է տալիս, որ սերվերը պատասխանատու է բոլոր առաջադրանքների համար, որոնք կապված են կապի մշակման հետ: Սա, օրինակ, աշխատում է TLS արձանագրության միջոցով: http.ListenAndServer զանգն իրականացնելու համար օգտագործվում է ստանդարտ HTTP սերվեր:
Այժմ դիտարկենք ավելի բարդ օրինակներ։
Let's Encrypt-ի ավելացում
Լռելյայնորեն, մեր հավելվածը աշխատում է HTTP արձանագրությամբ, սակայն խորհուրդ է տրվում օգտագործել HTTPS արձանագրությունը: Դա կարելի է անել առանց խնդիրների Go-ում: Եթե ստացել եք վկայական և անձնական բանալի, ապա բավական է գրանցել ListenAndServeTLS-ը ճիշտ վկայականով և բանալի ֆայլերով։
Եկեք շեղենք տրամադրում է անվճար վկայականներ՝ ավտոմատ թարմացմամբ: Ծառայությունից օգտվելու համար անհրաժեշտ է փաթեթ autocert.
Այն կարգավորելու ամենահեշտ ձևը autocert.NewListener մեթոդի օգտագործումն է՝ http.Serve-ի հետ համատեղ: Մեթոդը թույլ է տալիս ստանալ և թարմացնել TLS վկայագրերը, մինչ HTTP սերվերը մշակում է հարցումները.
Եթե բրաուզերում բացենք example.com, մենք կստանանք HTTPS պատասխան «Բարև, աշխարհ»:
Եթե Ձեզ անհրաժեշտ է ավելի մանրամասն կազմաձևում, ապա դուք պետք է օգտագործեք autocert.Manager մենեջերը: Այնուհետև մենք ստեղծում ենք մեր սեփական http.Server օրինակը (մինչ այժմ մենք օգտագործում էինք այն լռելյայն) և ավելացնում կառավարիչը TLSconfig սերվերին.
Սա HTTPS-ի ամբողջական աջակցությունն իրականացնելու հեշտ միջոց է՝ վկայագրի ավտոմատ նորացման միջոցով:
Հատուկ երթուղիների ավելացում
Ստանդարտ գրադարանում ներառված լռելյայն երթուղիչը լավն է, բայց այն շատ հիմնական է: Ծրագրերի մեծամասնությունը պահանջում է ավելի բարդ երթուղիներ, ներառյալ ներդիր և նիշերի երթուղիները, կամ ուղու օրինաչափությունների և պարամետրերի սահմանման ընթացակարգ:
Այս դեպքում արժե օգտագործել փաթեթներ գորիլա/մաքս и go-chi/chi. Մենք կսովորենք, թե ինչպես աշխատել վերջինիս հետ, օրինակ՝ ստորև:
Տրված է 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 ֆունկցիայի միջոցով: Այն վերադարձնում է մշակիչ, որը ֆայլեր է սպասարկում կոնկրետ գրացուցակից:
Միանշանակ արժե հիշել, որ 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 սերվերներ: