🌟

Goのhttpサーバーの基本構造とハンドラの実装

に公開

Goでは特定のポートを開いて、httpリクエストを受け取るための仕組みとして、net/httpパッケージが用意されています。よく使われるのは、http.ListenAndServe関数です。

http.ListenAndServe(":8080", handler)
  • 第一引数に開きたいポート番号
  • 第二引数に、リクエストを受けた時に実行したい処理(handler)を渡す

リクエストに含まれるパスに応じて実行したい処理を分けたい場合は、事前にルーティングを管理するオブジェクト(ex: ServeMux)を作成し、パスとhandlerのマッピングをしたものをListenAndServeに渡します。

mux := http.NewServeMux()
// パスとhandlerのマッピング
mux.HandleFunc("/hello", helloHandler)
http.ListenAndServe(":8080",mux)

Handlerとは

handlerはGoのhttp.Handlerインターフェースを満たす必要があります。
このインターフェースは次のように定義されています。

type Handler interface{
 ServeHTTP(http.ResponseWriter, *http.Request)
}
  • 第一引数:レスポンスの書き出しすための仕組み(インターフェース)
  • 第二引数:受け取ったリクエストを読み取るための仕組み(構造体)

次のように使います

// 空の構造体を定義する
type helloHandler struct{}

// helloHandler構造体にServeHTTPメソッドを定義する
func(h helloHandler) ServeHTTP(w http.ResponseWriter, r *http.Request){
 fmt.Fprintln(w, "hello")
}

//HelloHandlerをhttp.listenAndServeに渡すと、8080へリクエストが来た時にHelloHandlerが実行される
http.ListenAndServe(":8080", helloHandler{})

responseWriterの役割

wは、クライアントに返すHTTPレスポンスを書き込むためのインターフェースです。
wに書き込むとそれがHTTPレスポンスとしてクライアントに送られます

  • fmt.Fprintln(w,"Hello") : wに文字列を書き込んでいる
  • w.Write([]byte(...)) : 明示的にバイト列を返す
  • w.Header().set(...) : ヘッダー情報をセットする
  • w.WriteHeader(404) : ステータスコードをセットする

(http.HandleFuncという仕組みでは、関数をそのままhandlerにできる)

func helloHandler(w http.ResponseWriter, r *http.Request) {
    w.Header.Set("Content-Type", "text/plain")
    w.WriteHeader(http.StatusOK)
    fmt.Fprintln(w, "hello")
}

http.HandleFunc("/hello", helloHandler)

Requestの役割

クライアントから送られてきたリクエストの中身を読み取れる。

  • r.Method → HTTPメソッド(GET, POSTなど)
  • r.URL.Path → アクセスされたパス
  • r.Body → リクエストボディ
  • r.Header → リクエストのヘッダー
参考

https://pkg.go.dev/net/http

ListenAndServe

ListenAndServeは、

  • リクエストの受信を監視する
  • TCP接続を受け入れる
  • HTTPプロトコルを解析する
  • レスポンスを返す
    といった処理を裏で行ってくれています。なので、自分たちはServeHTTP(w,r)の中身だけに集中できます。

まとめ

TanStack ServerFunctionについて理解しようとしていたところ、そもそもHTTP Serverの仕組みがあやふやだったので、まとめてみました。このように、GoのHTTPサーバーは、net/httpパッケージだけでも柔軟に構築できます。

Discussion