Goのnet/httpの使い方を理解する必要があったのでまとめてみた。
メモ代わりにする。
http.ListenAndServe
サーバーを起動するよくあるやつ
・第1引数にPORT番号
・第2引数にhttp.Handler
http.ListenAndServe(":8080", nil)
http.Handler
ServeHTTPメソッドを定義しているinterface。つまりinterface。
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
http.ServeMux
ServeMux.Handleメソッドを使用して、URLとHandlerの登録ができる。
以下のようにすると/echoURLに対してechoHandlerを登録できる。これによってechoHandlerのServeHTTPメソッドが呼び出されるようになる。
つまり、HandlerInterfaceの実装を第2引数にわたすこととなる。
func main() {
mux := http.NewServeMux()
mux.Handle("/echo", echoHandler)
}
type echoHandler struct{}
func (h *echoHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
fmt.Fprintf(w, "Hello World")
}
http.HandlerFunc
HandlerFunc型はServeHTTP(ResponseWriter, *Request)
が実装されている。
そして、中ではキャストされたもとの関数を呼び出せるようになっているので以下のようにServeMux.Handleの第2引数とすることができる。
hello()をHandlerFunc型にキャストすることでServeHTTPがレシーバーとして勝手についてくる。
レシーバーのServeHTTPは紐付き先を呼び出しているだけ。
この仕組みにより、上記のechoHandlerのような構造体は必要なくなる。
type HandlerFunc func(ResponseWriter, *Request)
// ServeHTTP calls f(w, r).
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
f(w, r)
}
func hello(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
fmt.Fprintf(w, "Hello World")
}
func main() {
mux := http.NewServeMux()
mux.Handle("/hello", http.HandlerFunc(hello)) // helloをHandlerFuncにキャスト
}
http.ServeMux.HandleFunc
実装はこんな感じ
第2引数のhandlerを自身のHandleで呼び出している。
http.HandlerFuncでやっていたことが省略して書けるので便利。
func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
mux.Handle(pattern, HandlerFunc(handler))
}
MIddlewareのはさみ方
これまでの説明で最終的にhttp.ServeMux.handle
になんとかして、http.Handler, つまりHandler interfaceの実装を渡してあげればいいことがわかった。
このことから、http.ServeMux.HandleFuncなどから返されるHandler interfaceの実装を引数にとり、返り値をまたしてもHandler interfaceの実装としてあげるメソッドを実装すればmiddleware挟むことができる。
参考資料