๊ฐ„๋‹จํ•œ ๊ฒƒ๋ถ€ํ„ฐ ๋ณต์žกํ•œ ๊ฒƒ๊นŒ์ง€ Golang์—์„œ ์›น ์„œ๋ฒ„ ๊ฐœ๋ฐœ

๊ฐ„๋‹จํ•œ ๊ฒƒ๋ถ€ํ„ฐ ๋ณต์žกํ•œ ๊ฒƒ๊นŒ์ง€ Golang์—์„œ ์›น ์„œ๋ฒ„ ๊ฐœ๋ฐœ

XNUMX๋…„ ์ „์— ๋‚˜๋Š” ์‹œ์ž‘ํ–ˆ๋‹ค ๊ณ ํ”ผ์‹œ๋ฅผ ๊ฐœ๋ฐœํ•˜๋‹ค, Golang ํ•™์Šต์„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” Go๊ฐ€ ๋งŽ์€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ์˜ํ•ด ๋ณด์™„๋˜๋Š” ๊ฐ•๋ ฅํ•œ ์–ธ์–ด๋ผ๋Š” ๊ฒƒ์„ ๊นจ๋‹ฌ์•˜์Šต๋‹ˆ๋‹ค. Go๋Š” ๋‹ค์žฌ๋‹ค๋Šฅํ•ฉ๋‹ˆ๋‹ค. ํŠนํžˆ ์„œ๋ฒ„ ์ธก ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์‰ฝ๊ฒŒ ๊ฐœ๋ฐœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด ๋ฌธ์„œ๋Š” Go๋กœ ์„œ๋ฒ„๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๊ด€ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค. "Hello world!"์™€ ๊ฐ™์€ ๊ฐ„๋‹จํ•œ ๊ฒƒ๋ถ€ํ„ฐ ์‹œ์ž‘ํ•˜์—ฌ ๋‹ค์Œ ๊ธฐ๋Šฅ์„ ๊ฐ–์ถ˜ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์œผ๋กœ ๋งˆ๋ฌด๋ฆฌํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

- HTTPS์— ๋Œ€ํ•ด Let's Encrypt๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
- API ๋ผ์šฐํ„ฐ๋กœ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.
โ€” ๋ฏธ๋“ค์›จ์–ด ์ž‘์—….
- ์ •์  ํŒŒ์ผ์„ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.
- ์˜ฌ๋ฐ”๋ฅธ ์ข…๋ฃŒ.

Skillbox๋Š” ๋‹ค์Œ์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค. ์‹ค๊ธฐ ์ฝ”์Šค "์ฒ˜์Œ๋ถ€ํ„ฐ Python ๊ฐœ๋ฐœ์ž".

์•Œ๋ฆผ: "Habr"์˜ ๋ชจ๋“  ๋…์ž๋ฅผ ์œ„ํ•œ - "Habr" ํ”„๋กœ๋ชจ์…˜ ์ฝ”๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ Skillbox ๊ณผ์ •์— ๋“ฑ๋กํ•  ๋•Œ 10 ๋ฃจ๋ธ” ํ• ์ธ.

์•ˆ๋…•, ์„ธ์ƒ!

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

๊ทธ ํ›„ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์‹คํ–‰ํ•˜๊ณ  ํŽ˜์ด์ง€๋ฅผ ์—ด๋ฉด ๋กœ์ปฌ ํ˜ธ์ŠคํŠธ, ๊ทธ๋Ÿฌ๋ฉด "Hello, world!"๋ผ๋Š” ํ…์ŠคํŠธ๊ฐ€ ์ฆ‰์‹œ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค. (๋ฌผ๋ก  ๋ชจ๋“  ๊ฒƒ์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ž‘๋™ํ•˜๋Š” ๊ฒฝ์šฐ).

์šฐ๋ฆฌ๋Š” ๋‹ค์Œ์—์„œ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ๋ฐ˜๋ณต์ ์œผ๋กœ ์‚ฌ์šฉํ•  ๊ฒƒ์ด์ง€๋งŒ ๋จผ์ € ๋ชจ๋“  ๊ฒƒ์ด ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•˜๋Š”์ง€ ์ดํ•ดํ•ฉ์‹œ๋‹ค.

๋„ท/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๋ฅผ ์ฐจ๋ก€๋กœ ์ˆ˜๋ฝํ•˜๋Š” ๋˜ ๋‹ค๋ฅธ ํ•จ์ˆ˜๋ฅผ ๋ž˜ํ•‘ํ•ฉ๋‹ˆ๋‹ค.

์ฆ‰, Golang์˜ ํ•ธ๋“ค๋Ÿฌ๋Š” ํ”„๋กœ๊ทธ๋ž˜๋จธ์—๊ฒŒ ๋งŽ์€ ๊ธฐํšŒ๋ฅผ ์ œ๊ณตํ•˜๋Š” ๋‹จ์ผ ์ธํ„ฐํŽ˜์ด์Šค๋กœ ํ‘œํ˜„๋ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ๋ฏธ๋“ค์›จ์–ด๋Š” ์ฒ˜๋ฆฌ๊ธฐ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ตฌํ˜„๋˜๋ฉฐ ์—ฌ๊ธฐ์„œ ServeHTTP๋Š” ๋จผ์ € ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•œ ๋‹ค์Œ ๋‹ค๋ฅธ ์ฒ˜๋ฆฌ๊ธฐ์˜ ServeHTTP ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.

์œ„์—์„œ ์–ธ๊ธ‰ํ–ˆ๋“ฏ์ด ํ•ธ๋“ค๋Ÿฌ๋Š” ๋‹จ์ˆœํžˆ ์š”์ฒญ์— ๋Œ€ํ•œ ์‘๋‹ต์„ ๊ตฌ์„ฑํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ํŠน์ • ์‹œ๊ฐ„์— ์–ด๋–ค ํ•ธ๋“ค๋Ÿฌ๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๊นŒ?

๋ผ์šฐํŒ… ์š”์ฒญ

์˜ฌ๋ฐ”๋ฅธ ์„ ํƒ์„ ํ•˜๋ ค๋ฉด HTTP ๋ฉ€ํ‹ฐํ”Œ๋ ‰์„œ๋ฅผ ์‚ฌ์šฉํ•˜์‹ญ์‹œ์˜ค. ์—ฌ๋Ÿฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์—์„œ muxer ๋˜๋Š” ๋ผ์šฐํ„ฐ๋ผ๊ณ  ํ•˜์ง€๋งŒ ๋ชจ๋‘ ๋™์ผํ•ฉ๋‹ˆ๋‹ค. ๋ฉ€ํ‹ฐํ”Œ๋ ‰์„œ์˜ ๊ธฐ๋Šฅ์€ ์š”์ฒญ ๊ฒฝ๋กœ๋ฅผ ๋ถ„์„ํ•˜๊ณ  ์ ์ ˆํ•œ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ์„ ํƒํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋ณต์žกํ•œ ๋ผ์šฐํŒ…์— ๋Œ€ํ•œ ์ง€์›์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ ํƒ€์‚ฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. ๊ฐ€์žฅ ์ง„๋ณด ๋œ ๊ฒƒ ์ค‘ ํ•˜๋‚˜ ๊ณ ๋ฆด๋ผ/๋จน์Šค ะธ ๊ณ ์น˜/์น˜, ์ด๋Ÿฌํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ฌธ์ œ ์—†์ด ์ค‘๊ฐ„ ์ฒ˜๋ฆฌ๋ฅผ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋“ค์˜ ๋„์›€์œผ๋กœ ์™€์ผ๋“œ์นด๋“œ ๋ผ์šฐํŒ…์„ ์„ค์ •ํ•˜๊ณ  ๊ธฐํƒ€ ์—ฌ๋Ÿฌ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋“ค์˜ ์žฅ์ ์€ ํ‘œ์ค€ HTTP ์ฒ˜๋ฆฌ๊ธฐ์™€์˜ ํ˜ธํ™˜์„ฑ์ž…๋‹ˆ๋‹ค. ๊ฒฐ๊ณผ์ ์œผ๋กœ ๋‚˜์ค‘์— ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐ„๋‹จํ•œ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ผ๋ฐ˜์ ์ธ ์ƒํ™ฉ์—์„œ ๋ณต์žกํ•œ ํ”„๋ ˆ์ž„์›Œํฌ๋กœ ์ž‘์—…ํ•˜๋ ค๋ฉด ํ‘œ์ค€ ์†”๋ฃจ์…˜์ด ํ•„์š”ํ•˜์ง€ ์•Š์œผ๋ฉฐ ์ด๋Š” ๊ธฐ๋ณธ ์ฒ˜๋ฆฌ๊ธฐ ์‚ฌ์šฉ์„ ํฌ๊ฒŒ ๋ณต์žกํ•˜๊ฒŒ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ๊ธฐ๋ณธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์™€ ๊ฐ„๋‹จํ•œ ๋ผ์šฐํ„ฐ์˜ ์กฐํ•ฉ์œผ๋กœ ๋Œ€๋ถ€๋ถ„์˜ ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ฟผ๋ฆฌ ์ฒ˜๋ฆฌ

๋˜ํ•œ ๋“ค์–ด์˜ค๋Š” ์—ฐ๊ฒฐ์„ "์ˆ˜์‹ "ํ•˜๊ณ  ๋ชจ๋“  ์š”์ฒญ์„ ์˜ฌ๋ฐ”๋ฅธ ์ฒ˜๋ฆฌ๊ธฐ๋กœ ๋ฆฌ๋””๋ ‰์…˜ํ•˜๋Š” ๊ตฌ์„ฑ ์š”์†Œ๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. http.Server๋Š” ์ด ์ž‘์—…์— ์‰ฝ๊ฒŒ ๋Œ€์ฒ˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‹ค์Œ์€ ์„œ๋ฒ„๊ฐ€ ์—ฐ๊ฒฐ ์ฒ˜๋ฆฌ์™€ ๊ด€๋ จ๋œ ๋ชจ๋“  ์ž‘์—…์„ ๋‹ด๋‹นํ•จ์„ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ์ด๊ฒƒ์€ TLS ํ”„๋กœํ† ์ฝœ์—์„œ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. ํ‘œ์ค€ HTTP ์„œ๋ฒ„๋Š” http.ListenAndServer ํ˜ธ์ถœ์„ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

์ด์ œ ์ข€ ๋” ๋ณต์žกํ•œ ์˜ˆ๋ฅผ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

Let's Encrypt ์ถ”๊ฐ€

๊ธฐ๋ณธ์ ์œผ๋กœ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์€ HTTP ํ”„๋กœํ† ์ฝœ์„ ํ†ตํ•ด ์‹คํ–‰๋˜์ง€๋งŒ HTTPS ํ”„๋กœํ† ์ฝœ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. Go์—์„œ๋Š” ๋ฌธ์ œ ์—†์ด ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ธ์ฆ์„œ์™€ ๊ฐœ์ธ ํ‚ค๋ฅผ ๋ฐ›์•˜๋‹ค๋ฉด ์˜ฌ๋ฐ”๋ฅธ ์ธ์ฆ์„œ์™€ ํ‚ค ํŒŒ์ผ๋กœ ListenAndServeTLS๋ฅผ ์ž‘์„ฑํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

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

๋‹น์‹ ์€ ํ•ญ์ƒ ๋” ์ž˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์•”ํ˜ธํ™”ํ•˜์ž. ์ž๋™ ๊ฐฑ์‹  ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ๋Š” ๋ฌด๋ฃŒ ์ธ์ฆ์„œ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์„œ๋น„์Šค๋ฅผ ์ด์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ํŒจํ‚ค์ง€๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. autocert.

์„ค์ •ํ•˜๋Š” ๊ฐ€์žฅ ์‰ฌ์šด ๋ฐฉ๋ฒ•์€ http.Serve์™€ ํ•จ๊ป˜ autocert.NewListener ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•˜๋ฉด HTTP ์„œ๋ฒ„๊ฐ€ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๋™์•ˆ TLS ์ธ์ฆ์„œ๋ฅผ ์ˆ˜์‹ ํ•˜๊ณ  ๊ฐฑ์‹ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

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 ์ง€์›์„ ๊ตฌํ˜„ํ•˜๋Š” ์‰ฌ์šด ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.

์‚ฌ์šฉ์ž ์ง€์ • ๊ฒฝ๋กœ ์ถ”๊ฐ€

ํ‘œ์ค€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ํฌํ•จ๋œ ๊ธฐ๋ณธ ๋ผ์šฐํ„ฐ๋Š” ํ›Œ๋ฅญํ•˜์ง€๋งŒ ๋งค์šฐ ๊ธฐ๋ณธ์ ์ž…๋‹ˆ๋‹ค. ๋Œ€๋ถ€๋ถ„์˜ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—๋Š” ์ค‘์ฒฉ ๋ฐ ์™€์ผ๋“œ์นด๋“œ ๊ฒฝ๋กœ ๋˜๋Š” ๊ฒฝ๋กœ ํŒจํ„ด ๋ฐ ๋งค๊ฐœ๋ณ€์ˆ˜ ์„ค์ • ์ ˆ์ฐจ๋ฅผ ํฌํ•จํ•˜์—ฌ ๋” ๋ณต์žกํ•œ ๋ผ์šฐํŒ…์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

์ด ๊ฒฝ์šฐ ํŒจํ‚ค์ง€๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ณ ๋ฆด๋ผ/๋จน์Šค ะธ ๊ณ ์น˜/์น˜. ํ›„์ž๋กœ ์ž‘์—…ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ฐฐ์›๋‹ˆ๋‹ค. ์˜ˆ๊ฐ€ ์•„๋ž˜์— ๋‚˜์™€ ์žˆ์Šต๋‹ˆ๋‹ค.

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 ํ•ธ๋“ค๋Ÿฌ๋กœ ๋ž˜ํ•‘ํ•˜์—ฌ ์ธ์ฆ, ์••์ถ•, ๋กœ๊น… ๋ฐ ๊ธฐํƒ€ ๊ธฐ๋Šฅ์„ ๋น ๋ฅด๊ฒŒ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด 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

๊ธฐ๋ณธ 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๋Š” ๋‹ค์Œ์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค.

์ถœ์ฒ˜ : habr.com

์ฝ”๋ฉ˜ํŠธ๋ฅผ ์ถ”๊ฐ€