LoginSignup
3
1

More than 3 years have passed since last update.

【Go】ServeMux と DefaultServeMux の違いについて

Last updated at Posted at 2020-08-22

※注意: この記事ははあくまで個人学習用に整理しただけの記事で、内容としては不完全なものになります。読んでも参考にならない可能性が高いです。

ServeMux と DefaultServeMux の違いについて、具体的に把握したい。

ServeMux については不完全な内容ながら以下にメモした。
Go の ServeMux について

DefaultServeMux とは

公式ドキュメントには以下のようにコメントしてある。
https://golang.org/src/net/http/server.go?h=defaultServeMux#L2240

DefaultServeMux is the default ServeMux used by Serve.
DefaultServeMuxは、Serveが使用するデフォルトのServeMuxです。

var DefaultServeMux = &defaultServeMux

var defaultServeMux ServeMux

defaultServeMux は単なる変数名で、ServeMux 構造体のポインタが格納されている。

以下にはこのようにコメントがある
https://golang.org/src/net/http/server.go?h=defaultServeMux#L2527

// A Server defines parameters for running an HTTP server.
// The zero value for Server is a valid configuration.
type Server struct {
    Addr string

    Handler Handler // handler to invoke, http.DefaultServeMux if nil

handler to invoke, http.DefaultServeMux if nil
呼び出すハンドラ。 nil の場合は http.DefaultServeMux

そして、その実装が以下

// serverHandler delegates to either the server's Handler or
// DefaultServeMux and also handles "OPTIONS *" requests.
type serverHandler struct {
    srv *Server
}

func (sh serverHandler) ServeHTTP(rw ResponseWriter, req *Request) {
    handler := sh.srv.Handler
    if handler == nil {
        handler = DefaultServeMux // ここで DefaultServeMux が使用されている
    }
    if req.RequestURI == "*" && req.Method == "OPTIONS" {
        handler = globalOptionsHandler{}
    }
    handler.ServeHTTP(rw, req)
}

なるほど。結局 ServeMux と DefaultServeMux は同じ型だった。

ちなみに、上記の serverHander.ServeHTTP は以下で実行されている
https://golang.org/src/net/http/server.go?h=serve#L1925

func (c *conn) serve(ctx context.Context) {
    // 省略
    serverHandler{c.server}.ServeHTTP(w, w.req) // ここで実行

conn.serve は以下で実行されている
https://golang.org/src/net/http/server.go?h=serve#L2969

func (srv *Server) Serve(l net.Listener) error {
    // 省略
        go c.serve(connCtx) // ここで実行

Server.Serve は以下で実行されている
https://golang.org/src/net/http/server.go?h=serve#L2866

func (srv *Server) ListenAndServe() error {
    if srv.shuttingDown() {
        return ErrServerClosed
    }
    addr := srv.Addr
    if addr == "" {
        addr = ":http"
    }
    ln, err := net.Listen("tcp", addr)
    if err != nil {
        return err
    }
    return srv.Serve(ln) // ここで実行
}

Server.ListenAndServe は直接実行する場合もあるし、http. ListenAndServe から実行されることもある。
http.ListenAndServe 内の server.ListenAndServe 実行箇所は以下。
https://golang.org/src/net/http/server.go?h=serve#L3120

func ListenAndServe(addr string, handler Handler) error {
    server := &Server{Addr: addr, Handler: handler}
    return server.ListenAndServe() // ここで実行
}

例えば、以下のようにサーバーを作成した場合、DefaultServeMux ではなく http.NewServeMux() で作成した mux が使用されるが、

func main() {
    mux := http.NewServeMux()
    mux.HandleFunc("/", index)
    server := &http.Server{
        Addr:           config.Address,
        Handler:        mux, // Handler に mux を設定した場合、DefaultServeMux ではなくこれが使用される
        ReadTimeout:    time.Duration(config.ReadTimeout * int64(time.Second)),
        WriteTimeout:   time.Duration(config.WriteTimeout * int64(time.Second)),
        MaxHeaderBytes: 1 << 20,
    }
    server.ListenAndServe()
}

以下のようにサーバーを作成した場合は、 DefaultServeMux が使用されるということか。

func main() {
    http.Handle("/", &templateHandler{filename: "index.html"})
    // この場合、マルチプレクサを特に設定していない事になるため、DefaultServeMux が使用される
    if err := http.ListenAndServe(":8080", nil); err != nil {
        log.Fatal("ListenAndServe:", err)
    }
}

なるほど。一旦雑に理解。

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1