Π Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° Π²Π΅Π±-сСрвСров Π½Π° Golang β€” ΠΎΡ‚ простого ΠΊ слоТному

Π Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° Π²Π΅Π±-сСрвСров Π½Π° Golang — ΠΎΡ‚ простого ΠΊ слоТному

ΠŸΡΡ‚ΡŒ Π»Π΅Ρ‚ Π½Π°Π·Π°Π΄ я Π½Π°Ρ‡Π°Π» Ρ€Π°Π·Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°Ρ‚ΡŒ Gophish, это Π΄Π°Π»ΠΎ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡ‚ΡŒ ΠΈΠ·ΡƒΡ‡ΠΈΡ‚ΡŒ Golang. Π― понял, Ρ‡Ρ‚ΠΎ Go β€” ΠΌΠΎΡ‰Π½Ρ‹ΠΉ язык, возмоТности ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ³ΠΎ Π΄ΠΎΠΏΠΎΠ»Π½ΡΡŽΡ‚ΡΡ мноТСством Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊ. Go унивСрсалСн: Π² частности, с Π΅Π³ΠΎ ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ ΠΌΠΎΠΆΠ½ΠΎ Π±Π΅Π· ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌ Ρ€Π°Π·Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°Ρ‚ΡŒ сСрвСрныС прилоТСния.

Π­Ρ‚Π° ΡΡ‚Π°Ρ‚ΡŒΡ посвящСна написанию сСрвСра Π½Π° Go. НачнСм с простых Π²Π΅Ρ‰Π΅ΠΉ, Π²Ρ€ΠΎΠ΄Π΅ Β«Hello world!Β», Π° Π·Π°ΠΊΠΎΠ½Ρ‡ΠΈΠΌ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ΠΌ с Ρ‚Π°ΠΊΠΈΠΌΠΈ возмоТностями:

β€” ИспользованиС Let’s Encrypt для HTTPS.
β€” Π Π°Π±ΠΎΡ‚Π° Π² качСствС API-ΠΌΠ°Ρ€ΡˆΡ€ΡƒΡ‚ΠΈΠ·Π°Ρ‚ΠΎΡ€Π°.
β€” Π Π°Π±ΠΎΡ‚Π° с middleware.
β€” ΠžΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° статичСских Ρ„Π°ΠΉΠ»ΠΎΠ².
β€” ΠšΠΎΡ€Ρ€Π΅ΠΊΡ‚Π½ΠΎΠ΅ Π·Π°Π²Π΅Ρ€ΡˆΠ΅Π½ΠΈΠ΅ Ρ€Π°Π±ΠΎΡ‚Ρ‹.

Skillbox Ρ€Π΅ΠΊΠΎΠΌΠ΅Π½Π΄ΡƒΠ΅Ρ‚: ΠŸΡ€Π°ΠΊΡ‚ΠΈΡ‡Π΅ΡΠΊΠΈΠΉ курс Β«Python-Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊ с нуля».

НапоминаСм: для всСх Ρ‡ΠΈΡ‚Π°Ρ‚Π΅Π»Π΅ΠΉ Β«Π₯Π°Π±Ρ€Π°Β» β€” скидка 10 000 Ρ€ΡƒΠ±Π»Π΅ΠΉ ΠΏΡ€ΠΈ записи Π½Π° любой курс Skillbox ΠΏΠΎ ΠΏΡ€ΠΎΠΌΠΎΠΊΠΎΠ΄Ρƒ Β«Π₯Π°Π±Ρ€Β».

Hello, world!

Π‘ΠΎΠ·Π΄Π°Ρ‚ΡŒ Π²Π΅Π±-сСрвСр Π½Π° Go ΠΌΠΎΠΆΠ½ΠΎ ΠΎΡ‡Π΅Π½ΡŒ быстро. Π’ΠΎΡ‚ ΠΏΡ€ΠΈΠΌΠ΅Ρ€ использования ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠ°, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ ΠΎΠ±Π΅Ρ‰Π°Π½Π½Ρ‹ΠΉ Π²Ρ‹ΡˆΠ΅ Β«Hello, world!Β».

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

ПослС этого, Ссли Π·Π°ΠΏΡƒΡΡ‚ΠΈΡ‚ΡŒ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΠΈ ΠΎΡ‚ΠΊΡ€Ρ‹Ρ‚ΡŒ страницу localhost, Ρ‚ΠΎ Π²Ρ‹ сразу ΡƒΠ²ΠΈΠ΄ΠΈΡ‚Π΅ тСкст Β«Hello, world!Β» (ΠΊΠΎΠ½Π΅Ρ‡Π½ΠΎ, Ссли всС Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚ ΠΏΡ€Π°Π²ΠΈΠ»ΡŒΠ½ΠΎ).

Π”Π°Π»Π΅Π΅ ΠΌΡ‹ Π±ΡƒΠ΄Π΅ΠΌ Π½Π΅ΠΎΠ΄Π½ΠΎΠΊΡ€Π°Ρ‚Π½ΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊ, Π½ΠΎ сначала Π΄Π°Π²Π°ΠΉΡ‚Π΅ ΠΏΠΎΠΉΠΌΠ΅ΠΌ, ΠΊΠ°ΠΊ всС устроСно.

net/http

Π’ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π΅ использовался ΠΏΠ°ΠΊΠ΅Ρ‚ net/http, это основноС срСдство Π² Go для Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ ΠΊΠ°ΠΊ сСрвСров, Ρ‚Π°ΠΊ ΠΈ HTTP-ΠΊΠ»ΠΈΠ΅Π½Ρ‚ΠΎΠ². Для Ρ‚ΠΎΠ³ΠΎ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΏΠΎΠ½ΡΡ‚ΡŒ ΠΊΠΎΠ΄, Π΄Π°Π²Π°ΠΉΡ‚Π΅ разбСрСмся Π² Π·Π½Π°Ρ‡Π΅Π½ΠΈΠΈ Ρ‚Ρ€Π΅Ρ… Π²Π°ΠΆΠ½Ρ‹Ρ… элСмСнтов: http.Handler, http.ServeMux ΠΈ http.Server.

HTTP-ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠΈ

Когда ΠΌΡ‹ ΠΏΠΎΠ»ΡƒΡ‡Π°Π΅ΠΌ запрос, ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊ Π°Π½Π°Π»ΠΈΠ·ΠΈΡ€ΡƒΠ΅Ρ‚ Π΅Π³ΠΎ ΠΈ Ρ„ΠΎΡ€ΠΌΠΈΡ€ΡƒΠ΅Ρ‚ ΠΎΡ‚Π²Π΅Ρ‚. ΠžΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠΈ Π² Go Ρ€Π΅Π°Π»ΠΈΠ·ΠΎΠ²Π°Π½Ρ‹ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΌ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ:

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

Π’ ΠΏΠ΅Ρ€Π²ΠΎΠΌ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π΅ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ Π²ΡΠΏΠΎΠΌΠΎΠ³Π°Ρ‚Π΅Π»ΡŒΠ½Π°Ρ функция http.HandleFunc. Она ΠΎΠ±ΠΎΡ€Π°Ρ‡ΠΈΠ²Π°Π΅Ρ‚ Π΄Ρ€ΡƒΠ³ΡƒΡŽ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ, которая, Π² свою ΠΎΡ‡Π΅Ρ€Π΅Π΄ΡŒ, ΠΏΡ€ΠΈΠ½ΠΈΠΌΠ°Π΅Ρ‚ http.ResponseWriter ΠΈ http.Request Π² ServeHTTP.

Π”Ρ€ΡƒΠ³ΠΈΠΌΠΈ словами, ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠΈ Π² Golang прСдставлСны Π΅Π΄ΠΈΠ½Ρ‹ΠΌ интСрфСйсом, Ρ‡Ρ‚ΠΎ Π΄Π°Π΅Ρ‚ мноТСство возмоТностСй для программиста. Π’Π°ΠΊ, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, middleware Ρ€Π΅Π°Π»ΠΈΠ·ΠΎΠ²Π°Π½ΠΎ ΠΏΡ€ΠΈ ΠΏΠΎΠΌΠΎΡ‰ΠΈ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠ°, Π³Π΄Π΅ ServeHTTP сначала Ρ‡Ρ‚ΠΎ-Ρ‚ΠΎ Π΄Π΅Π»Π°Π΅Ρ‚, Π° Π·Π°Ρ‚Π΅ΠΌ Π²Ρ‹Π·Ρ‹Π²Π°Π΅Ρ‚ ΠΌΠ΅Ρ‚ΠΎΠ΄ ServeHTTP Π΄Ρ€ΡƒΠ³ΠΎΠ³ΠΎ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠ°.

Как ΠΈ Π³ΠΎΠ²ΠΎΡ€ΠΈΠ»ΠΎΡΡŒ Π²Ρ‹ΡˆΠ΅, ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠΈ просто Ρ„ΠΎΡ€ΠΌΠΈΡ€ΡƒΡŽΡ‚ ΠΎΡ‚Π²Π΅Ρ‚Ρ‹ Π½Π° запросы. Но ΠΊΠ°ΠΊΠΎΠΉ ΠΈΠΌΠ΅Π½Π½ΠΎ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊ Π½ΡƒΠΆΠ½ΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Π² ΠΊΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½Ρ‹ΠΉ ΠΌΠΎΠΌΠ΅Π½Ρ‚ Π²Ρ€Π΅ΠΌΠ΅Π½ΠΈ?

ΠœΠ°Ρ€ΡˆΡ€ΡƒΡ‚ΠΈΠ·Π°Ρ†ΠΈΡ запросов

Для Ρ‚ΠΎΠ³ΠΎ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ ΠΏΡ€Π°Π²ΠΈΠ»ΡŒΠ½Ρ‹ΠΉ Π²Ρ‹Π±ΠΎΡ€, Π²ΠΎΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠΉΡ‚Π΅ΡΡŒ HTTP-ΠΌΡƒΠ»ΡŒΡ‚ΠΈΠΏΠ»Π΅ΠΊΡΠΎΡ€ΠΎΠΌ. Π’ рядС Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊ Π΅Π³ΠΎ Π½Π°Π·Ρ‹Π²Π°ΡŽΡ‚ muxer ΠΈΠ»ΠΈ router, Π½ΠΎ всС это ΠΎΠ΄Π½ΠΎ ΠΈ Ρ‚ΠΎ ΠΆΠ΅. Ѐункция ΠΌΡƒΠ»ΡŒΡ‚ΠΈΠΏΠ»Π΅ΠΊΡΠΎΡ€Π° Π·Π°ΠΊΠ»ΡŽΡ‡Π°Π΅Ρ‚ΡΡ Π² Π°Π½Π°Π»ΠΈΠ·Π΅ ΠΏΡƒΡ‚ΠΈ запроса ΠΈ Π²Ρ‹Π±ΠΎΡ€Π΅ ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΡ‚Π²ΡƒΡŽΡ‰Π΅Π³ΠΎ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠ°.

Если ΠΆΠ΅ Π½ΡƒΠΆΠ½Π° ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΊΠ° слоТной ΠΌΠ°Ρ€ΡˆΡ€ΡƒΡ‚ΠΈΠ·Π°Ρ†ΠΈΠΈ, Ρ‚ΠΎΠ³Π΄Π° Π»ΡƒΡ‡ΡˆΠ΅ Π²ΠΎΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒΡΡ сторонними Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ°ΠΌΠΈ. Одни ΠΈΠ· Π½Π°ΠΈΠ±ΠΎΠ»Π΅Π΅ ΠΏΡ€ΠΎΠ΄Π²ΠΈΠ½ΡƒΡ‚Ρ‹Ρ… β€” gorilla/mux ΠΈ go-chi/chi, эти Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈ Π΄Π°ΡŽΡ‚ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡ‚ΡŒ Ρ€Π΅Π°Π»ΠΈΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΠΏΡ€ΠΎΠΌΠ΅ΠΆΡƒΡ‚ΠΎΡ‡Π½ΡƒΡŽ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΡƒ Π±Π΅Π· особых ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌ. Π‘ ΠΈΡ… ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ ΠΌΠΎΠΆΠ½ΠΎ Π½Π°ΡΡ‚Ρ€ΠΎΠΈΡ‚ΡŒ wildcard-ΠΌΠ°Ρ€ΡˆΡ€ΡƒΡ‚ΠΈΠ·Π°Ρ†ΠΈΡŽ ΠΈ Π²Ρ‹ΠΏΠΎΠ»Π½ΠΈΡ‚ΡŒ ряд Π΄Ρ€ΡƒΠ³ΠΈΡ… Π·Π°Π΄Π°Ρ‡. Π˜Ρ… плюс β€” ΡΠΎΠ²ΠΌΠ΅ΡΡ‚ΠΈΠΌΠΎΡΡ‚ΡŒ со стандартными HTTP-ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠ°ΠΌΠΈ. Π’ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Π΅ Π²Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Π½Π°ΠΏΠΈΡΠ°Ρ‚ΡŒ простой ΠΊΠΎΠ΄ с Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡ‚ΡŒΡŽ Π΅Π³ΠΎ ΠΌΠΎΠ΄ΠΈΡ„ΠΈΠΊΠ°Ρ†ΠΈΠΈ Π² Π±ΡƒΠ΄ΡƒΡ‰Π΅ΠΌ.

Π Π°Π±ΠΎΡ‚Π° со слоТными Ρ„Ρ€Π΅ΠΉΠΌΠ²ΠΎΡ€ΠΊΠ°ΠΌΠΈ Π² ΠΎΠ±Ρ‹Ρ‡Π½ΠΎΠΉ ситуации ΠΏΠΎΡ‚Ρ€Π΅Π±ΡƒΠ΅Ρ‚ Π½Π΅ совсСм стандартных Ρ€Π΅ΡˆΠ΅Π½ΠΈΠΉ, Π° это Π·Π½Π°Ρ‡ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎ услоТняСт использованиС Π΄Π΅Ρ„ΠΎΠ»Ρ‚Π½Ρ‹Ρ… ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠΎΠ². Для создания ΠΏΠΎΠ΄Π°Π²Π»ΡΡŽΡ‰Π΅Π³ΠΎ Π±ΠΎΠ»ΡŒΡˆΠΈΠ½ΡΡ‚Π²Π° ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ Ρ…Π²Π°Ρ‚ΠΈΡ‚ ΠΊΠΎΠΌΠ±ΠΈΠ½Π°Ρ†ΠΈΠΈ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈ ΠΏΠΎ ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ ΠΈ нСслоТного ΠΌΠ°Ρ€ΡˆΡ€ΡƒΡ‚ΠΈΠ·Π°Ρ‚ΠΎΡ€Π°.

ΠžΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° запросов

ΠšΡ€ΠΎΠΌΠ΅ Ρ‚ΠΎΠ³ΠΎ, Π½Π°ΠΌ Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Π±ΡƒΠ΄Π΅Ρ‚ Β«ΡΠ»ΡƒΡˆΠ°Ρ‚ΡŒΒ» входящиС соСдинСния ΠΈ ΠΏΠ΅Ρ€Π΅Π½Π°ΠΏΡ€Π°Π²Π»ΡΡ‚ΡŒ всС запросы ΠΏΡ€Π°Π²ΠΈΠ»ΡŒΠ½ΠΎΠΌΡƒ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΡƒ. Π‘ этой Π·Π°Π΄Π°Ρ‡Π΅ΠΉ Π±Π΅Π· Ρ‚Ρ€ΡƒΠ΄Π° справится http.Server.

НиТС ΠΏΠΎΠΊΠ°Π·Π°Π½ΠΎ, Ρ‡Ρ‚ΠΎ сСрвСр ΠΎΡ‚Π²Π΅Ρ‡Π°Π΅Ρ‚ Π·Π° всС Π·Π°Π΄Π°Ρ‡ΠΈ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΈΠΌΠ΅ΡŽΡ‚ ΠΎΡ‚Π½ΠΎΡˆΠ΅Π½ΠΈΠ΅ ΠΊ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ΅ соСдинСний. Π­Ρ‚ΠΎ, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, Ρ€Π°Π±ΠΎΡ‚Π° ΠΏΠΎ ΠΏΡ€ΠΎΡ‚ΠΎΠΊΠΎΠ»Ρƒ TLS. Для Ρ€Π΅Π°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ Π²Ρ‹Π·ΠΎΠ²Π° http.ListenAndServer ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ стандартный HTTP-сСрвСр.

Π’Π΅ΠΏΠ΅Ρ€ΡŒ Π΄Π°Π²Π°ΠΉΡ‚Π΅ рассмотрим Π±ΠΎΠ»Π΅Π΅ слоТныС ΠΏΡ€ΠΈΠΌΠ΅Ρ€Ρ‹.

Π”ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΠ΅ Let’s Encrypt

По ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ нашС ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚ ΠΏΠΎ HTTP-ΠΏΡ€ΠΎΡ‚ΠΎΠΊΠΎΠ»Ρƒ, ΠΎΠ΄Π½Π°ΠΊΠΎ рСкомСндуСтся ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΠΏΡ€ΠΎΡ‚ΠΎΠΊΠΎΠ» HTTPS. Π’ Go это ΠΌΠΎΠΆΠ½ΠΎ ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ Π±Π΅Π· ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌ. Если Π²Ρ‹ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΠ»ΠΈ сСртификат ΠΈ Π·Π°ΠΊΡ€Ρ‹Ρ‚Ρ‹ΠΉ ΠΊΠ»ΡŽΡ‡, Ρ‚ΠΎΠ³Π΄Π° достаточно ΠΏΡ€ΠΎΠΏΠΈΡΠ°Ρ‚ΡŒ ListenAndServeTLS с ΡƒΠΊΠ°Π·Π°Π½ΠΈΠ΅ΠΌ ΠΏΡ€Π°Π²ΠΈΠ»ΡŒΠ½Ρ‹Ρ… Ρ„Π°ΠΉΠ»ΠΎΠ² сСртификата ΠΈ ΠΊΠ»ΡŽΡ‡Π°.

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

ВсСгда ΠΌΠΎΠΆΠ½ΠΎ ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ Π»ΡƒΡ‡ΡˆΠ΅.

Let’s Encrypt Π΄Π°Π΅Ρ‚ бСсплатныС сСртификаты с Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡ‚ΡŒΡŽ автоматичСского обновлСния. Для Ρ‚ΠΎΠ³ΠΎ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π²ΠΎΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒΡΡ сСрвисом, Π½ΡƒΠΆΠ΅Π½ ΠΏΠ°ΠΊΠ΅Ρ‚ autocert.

Π‘Π°ΠΌΡ‹ΠΉ простой способ Π΅Π³ΠΎ Π½Π°ΡΡ‚Ρ€ΠΎΠΈΡ‚ΡŒ β€” Π²ΠΎΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒΡΡ ΠΌΠ΅Ρ‚ΠΎΠ΄ΠΎΠΌ autocert.NewListener Π² ΠΊΠΎΠΌΠ±ΠΈΠ½Π°Ρ†ΠΈΠΈ с http.Serve. ΠœΠ΅Ρ‚ΠΎΠ΄ позволяСт ΠΏΠΎΠ»ΡƒΡ‡Π°Ρ‚ΡŒ ΠΈ ΠΎΠ±Π½ΠΎΠ²Π»ΡΡ‚ΡŒ TLS-сСртификаты, Π² Ρ‚ΠΎ врСмя ΠΊΠ°ΠΊ HTTP-сСрвСр ΠΎΠ±Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°Π΅Ρ‚ запросы:

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

Если ΠΌΡ‹ ΠΎΡ‚ΠΊΡ€ΠΎΠ΅ΠΌ Π² Π±Ρ€Π°ΡƒΠ·Π΅Ρ€Π΅ example.com, Ρ‚ΠΎ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΠΌ HTTPS-ΠΎΡ‚Π²Π΅Ρ‚ Β«Hello, world!Β».

Если Π½ΡƒΠΆΠ½Π° Π±ΠΎΠ»Π΅Π΅ Ρ‚Ρ‰Π°Ρ‚Π΅Π»ΡŒΠ½Π°Ρ настройка, Ρ‚ΠΎ стоит Π²ΠΎΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒΡΡ ΠΌΠ΅Π½Π΅Π΄ΠΆΠ΅Ρ€ΠΎΠΌ 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 с автоматичСским ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½ΠΈΠ΅ΠΌ сСртификата.

Π”ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΠ΅ нСстандартных ΠΌΠ°Ρ€ΡˆΡ€ΡƒΡ‚ΠΎΠ²

Π”Π΅Ρ„ΠΎΠ»Ρ‚Π½Ρ‹ΠΉ ΠΌΠ°Ρ€ΡˆΡ€ΡƒΡ‚ΠΈΠ·Π°Ρ‚ΠΎΡ€, Π²ΠΊΠ»ΡŽΡ‡Π΅Π½Π½Ρ‹ΠΉ Π² ΡΡ‚Π°Π½Π΄Π°Ρ€Ρ‚Π½ΡƒΡŽ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΡƒ, Ρ…ΠΎΡ€ΠΎΡˆ, Π½ΠΎ ΠΎΠ½ ΠΎΡ‡Π΅Π½ΡŒ простой. Π’ Π±ΠΎΠ»ΡŒΡˆΠΈΠ½ΡΡ‚Π²Π΅ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ Π½ΡƒΠΆΠ½Π° Π±ΠΎΠ»Π΅Π΅ слоТная ΠΌΠ°Ρ€ΡˆΡ€ΡƒΡ‚ΠΈΠ·Π°Ρ†ΠΈΡ, Π²ΠΊΠ»ΡŽΡ‡Π°Ρ Π²Π»ΠΎΠΆΠ΅Π½Π½Ρ‹Π΅ ΠΈ wildcard-ΠΌΠ°Ρ€ΡˆΡ€ΡƒΡ‚Ρ‹ ΠΈΠ»ΠΈ ΠΆΠ΅ ΠΏΡ€ΠΎΡ†Π΅Π΄ΡƒΡ€Ρƒ установки шаблонов ΠΈ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ΠΎΠ² ΠΏΡƒΡ‚Π΅ΠΉ.

Π’ этом случаС стоит ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΠΏΠ°ΠΊΠ΅Ρ‚Ρ‹ gorilla/mux ΠΈ 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 Π² основном Ρ„Π°ΠΉΠ»Π΅.

We can then mount this to our main router under the api/v1/ prefix back in our 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())

ΠŸΡ€ΠΎΡΡ‚ΠΎΡ‚Π° Ρ€Π°Π±ΠΎΡ‚Ρ‹ со слоТными ΠΌΠ°Ρ€ΡˆΡ€ΡƒΡ‚Π°ΠΌΠΈ Π² Go Π΄Π΅Π»Π°Π΅Ρ‚ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½Ρ‹ΠΌ ΡƒΠΏΡ€ΠΎΡΡ‚ΠΈΡ‚ΡŒ ΡΡ‚Ρ€ΡƒΠΊΡ‚ΡƒΡ€ΠΈΠ·Π°Ρ†ΠΈΡŽ с обслуТиваниСм Π±ΠΎΠ»ΡŒΡˆΠΈΡ… комплСксных ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ.

Π Π°Π±ΠΎΡ‚Π° с middleware

Π’ случаС ΠΏΡ€ΠΎΠΌΠ΅ΠΆΡƒΡ‚ΠΎΡ‡Π½ΠΎΠΉ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ ΠΎΠ±ΠΎΡ€Π°Ρ‡ΠΈΠ²Π°Π½ΠΈΠ΅ ΠΎΠ΄Π½ΠΎΠ³ΠΎ 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. Она Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Ρ€Π°Π·Π΄Π°Π΅Ρ‚ Ρ„Π°ΠΉΠ»Ρ‹ ΠΈΠ· ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½Π½ΠΎΠΉ Π΄ΠΈΡ€Π΅ΠΊΡ‚ΠΎΡ€ΠΈΠΈ.

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 Ρ€Π΅ΠΊΠΎΠΌΠ΅Π½Π΄ΡƒΠ΅Ρ‚:

Π˜ΡΡ‚ΠΎΡ‡Π½ΠΈΠΊ: habr.com