何もしないサーバを起動。
package main
import "net/http"
func main() {
http.ListenAndServe("", nil)
}
ListenAndServe
はネットワークアドレスとハンドラを引数で受け取る。ハンドラが nil の場合は DefaultServerMux
が使われる。
Server の構造体はこんな感じ。
type Server struct {
Addr string
Handler Handler
TLSConfig *tls.Config
ReadTimeout time.Duration
ReadHeaderTimeout time.Duration
WriteTimeout time.Duration
IdleTimeout time.Duration
MaxHeaderBytes int
TLSNextProto map[string]func(*Server, *tls.Conn, Handler)
ConnState func(net.Conn, ConnState)
ErrorLog *log.Logger
BaseContext func(net.Listener) context.Context
ConnContext func(ctx context.Context, c net.Conn) context.Context
inShutdown atomicBool
disableKeepAlives int32
nextProtoOnce sync.Once
nextProtoErr error
mu sync.Mutex
listeners map[*net.Listener]struct{}
activeConn map[*conn]struct{}
doneChan chan struct{}
onShutdown []func()
}
設定を変更する場合は Server の構造体に値を指定する。
func main() {
server := http.Server{
Addr: "0.0.0.0:8080",
Handler: nil,
}
server.ListenAndServe()
ハンドラがない場合すべてのリクエストで 404 を返す。
ハンドラとは、 ServerHTTP メソッド
を持ったインターフェースのことを指す。
このメソッドは、 インターフェース HTTPResponseWriter
と 構造体 Request のポインタ
の 2 つの引数を取る。
つまり、 ServerHTTP(http.ResponseWriter, *http.Request)
をもつインターフェースがハンドラになる。
type HelloHandler struct{}
func (h *HelloHandler) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
fmt.Fprintf(writer, "hello")
}
func main() {
helloHandler := new(HelloHandler)
server := http.Server{
Addr: "0.0.0.0:8080",
Handler: helloHandler,
}
server.ListenAndServe()
}
この状態だと、すべてのアクセスが 1 つのハンドラに行く。
実際は URL ごとに異なるハンドラで処理する必要があるため Handler フィールドに値を指定しない ( デフォルトで DefaultServerMux を使う ) 。
type HelloHandler struct{}
type WorldHandler struct{}
func (h *HelloHandler) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
fmt.Fprintf(writer, "hello")
}
func (w *WorldHandler) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
fmt.Fprintf(writer, "world")
}
func main() {
helloHandler := new(HelloHandler)
worldHandler := new(WorldHandler)
server := http.Server{
Addr: "0.0.0.0:8080",
}
http.Handle("/hello", helloHandler)
http.Handle("/world", worldHandler)
server.ListenAndServe()
}
http.Handle
は実際には DefaultServeMux の Handle メソッドを呼び出している。
func Handle(pattern string, handler Handler) { DefaultServeMux.Handle(pattern, handler) }
ハンドラとは、 ServerHTTP(http.ResponseWriter, *http.Request)
をもつインターフェースのこと。
ハンドラ関数とは、ハンドラのように振る舞う関数。リクエストのポインタを受け取ることができる。
package main
import (
"fmt"
"net/http"
)
type HelloHandler struct{}
type WorldHandler struct{}
func (h *HelloHandler) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
fmt.Fprintf(writer, "hello")
}
func (w *WorldHandler) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
fmt.Fprintf(writer, "world")
}
func hello(writer http.ResponseWriter, request *http.Request) {
fmt.Fprintf(writer, "hello")
}
func world(writer http.ResponseWriter, request *http.Request) {
fmt.Fprintf(writer, "world")
}
func main() {
helloHandler := new(HelloHandler)
worldHandler := new(WorldHandler)
server := http.Server{
Addr: "0.0.0.0:8080",
}
http.Handle("/hello", helloHandler)
http.Handle("/world", worldHandler)
http.HandleFunc("/hello2", hello)
http.HandleFunc("/world2", world)
server.ListenAndServe()
}
やってることは DefaultServeMux.Handle(pattern, handler)
なので同じ。
既存のインターフェースがある場合は、 ServeHTTP
メソッドを追加するだけでハンドラになるからそういった場合は、 http.Handle
のほうが手軽。
func Handle(pattern string, handler Handler) { DefaultServeMux.Handle(pattern, handler) }
func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
DefaultServeMux.HandleFunc(pattern, handler)
}
func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
if handler == nil {
panic("http: nil handler")
}
mux.Handle(pattern, HandlerFunc(handler))
}
標準でも特に辛くない。 request.Method
でメソッドも取得できるのでかなり使い勝手もいい。
mux.HandleFunc("/users/create", createUsers)
mux.HandleFunc("/users/read/", readUsers)
mux.HandleFunc("/users/update/", updateUsers)
mux.HandleFunc("/users/delete/", deleteUsers)
func readerUsers(writer http.ResponseWriter, request *http.Request) {
sub := strings.TrimPrefix(request.URL.Path, "/users/read/")
userId, err := strconv.Atoi(sub) // これで /users/read/:id の id を取得できる
}
下記のような、 /users/:user_id/tasks/:task_id
みたいに解析を結構頑張らないといけない場合は結構辛い。
mux.HandleFunc("/users/2/tasks/create", createUsers)
mux.HandleFunc("/users/2/tasks/read/", readUsers)
mux.HandleFunc("/users/2/tasks/update/", updateUsers)
mux.HandleFunc("/users/2/tasks/delete/", deleteUsers)
この辺が良さそう。