'sqr'atch-note

ちりはつもれど ちりぬるを

http.Handleとhttp.HandleFuncの整理

Golangの標準ライブラリであるnet/httpを使っていると、http.Handleとhttp.HandleFunc、Handler、HandlerFuncとがあって、ごっちゃになってしまうので、自分なりに整理をした。

  • net/httpライブラリを使ってサーバを起動する(http.ListenAndServe)と、デフォルトのマルチプレクサー;mux(ルーター)が生成される
  • このmuxに対してURLパスとHTTPハンドラを登録することで、リクエストを受けたりレスポンスを返したり出来る。登録する仕組みとしては、
    • http.Handle(pattern string, handler Handler)
    • http.HandleFunc(pattern string, handler func(ResponseWriter, *Request))
  • の2つが用意されている
  • この2つの違いは、引数にHandlerインターフェイスを受け取るか、HandlerFunc型を受け取るかの違いでしかない
  • まず、Handlerインターフェイスの定義は、以下の通りServeHTTPメソッドだけが定義されている
type Handler interface {
    ServeHTTP(http.ResponseWrite, *http.Request)
}
  • 次にHandlerFunc型は関数型であり、以下のように定義されている。
  • type HandlerFunc func(ResponseWriter, *Request)
  • そして、HandlerFunc型にはServeHTTPメソッドが定義されている。
    • このServeHTTPは、レシーバで受け取ったHandlerFunc型を返すだけのメソッドとなっている。
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
  f(w, r)
}
  • したがって、HandlerFunc型と同じシグネチャを持つ任意の関数MyFuncをhttp.HandlerFunc(MyFunc)のようにキャストすると、MyFuncに対してHandlerFuncが持つメソッドServeHTTP()が実装される。
    • func MyFunc(w http.ResponseWriter, r *http.Request) {// do something }
    • MyHandler := http.HandlerFunc(MyFunc)
  • 結果、暗黙的にHandlerインターフェイスを実装する(満たす)ことになる。よって、myFuncは、Handlerインターフェイス型として扱えるので、http.Handleの第2引数として渡せる。
    • http.Handle("/myfunc", MyHandler)
  • じゃあ、この二つの使い分け方はどうするのか?という点だけど、力尽きてしまったのでChatGPTに聞いてみると次のような簡潔な回答を得られた。

使い分け方
- シンプルなハンドラーが必要な場合、または匿名関数で簡潔に処理を記述したい場合は、http.HandleFuncを使用します。
- 状態を持つハンドラーや、複数のメソッドやロジックを持たせたカスタムハンドラーが必要な場合には、http.Handleを使い、構造体やカスタム型を渡すことで柔軟に実装します。
まとめ
- http.HandleFunc: 関数を簡単にハンドラーにしたいときに便利。
- http.Handle: http.Handlerインターフェースを満たす型をハンドラーとして登録し、より複雑な処理を行いたいときに使います。