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インターフェースを満たす型をハンドラーとして登録し、より複雑な処理を行いたいときに使います。