はじめに
- Go 言語では以下のような簡単なコードでウェブサーバーを立ち上げることができますが、正確に意味を理解しておらずイディオムとして使っていたので整理するために一回ちゃんと調べてみました。
package main
import (
"fmt"
"net/http"
)
func main() {
http.HandleFunc("/hello", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello World")
})
log.Fatal(http.ListenAndServe(":8080", nil))
}
http.Handler とは
-
http.HandlerとはServeHTTP関数を持つだけのインターフェイスで HTTP リクエストを受けてレスポンスを返すことを責務とします。
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
http.Handle とは
func Handle(pattern string, handler Handler) { DefaultServeMux.Handle(pattern, handler) }
-
http.Handleとは表示する URL と、URL に対応するhttp.HandlerをDefaultServeMuxに登録する関数です。 -
DefaultServeMuxとはデフォルトでhttp.ServeMux型の構造体で URL に対応したhttp.Handlerを実行するいわゆるルーターです。 - また
DefaultServeMuxはルーターであると同時にServeHTTP関数を持つhttp.Handlerです。 -
http.ListenAndServeの第二引数が nil の場合DefaultServeMuxが Handler として指定されます。自分が分かりづらかったのはここでhttp.ListenAndServeが Handler を受け取ったりgorilla/muxのようなルーターを受け取ったりしていたので混乱しました。全てがhttp.Handlerなんだと理解できてからはすっきりしました。 - 以下の 1 と 2 と 3 はだいたい同じ意味の処理になります。
type AnyHandler struct {}
func (a *AnyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {}
anyHandler := &AnyHandler{}
// 1
http.Handle("/any/", anyHandler)
http.ListenAndServe(":8080", nil)
// 2
mux := http.NewServeMux()
mux.Handle("/any/", anyHandler)
http.ListenAndServe(":8080", mux)
// 3
http.ListenAndServe(":8080", http.HandleFunc(func(w http.ResponseWriter, r *http.Request){
if r.URL.Path == "/any/" {
anyHandler.ServeHTTP(w, r)
}
}))
http.HandlerFunc とは
-
func(ResponseWriter, *Request)の別名の型でServeHTTP関数を持つので、関数を定義してhttp.HandlerFuncにキャストするだけで構造体を宣言することなくhttp.Handlerを用意することができます。
type HandlerFunc func(ResponseWriter, *Request)
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
f(w, r)
}
http.HandleFunc とは
func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
DefaultServeMux.HandleFunc(pattern, handler)
}
- URL と
func(ResponseWriter, *Request)を渡してDefaultServeMuxに登録する関数です。 - 内部で
func(ResponseWriter, *Request)からhttp.HandlerFuncへのキャストが行われています。
さいごに
- 全部ドキュメントに載っていて読めってはなしなのでドキュメント大切。