ServeHTTP が理解できません - このコードはどのように動作するのでしょうか? 質問する

ServeHTTP が理解できません - このコードはどのように動作するのでしょうか? 質問する

私は Golang で Web 開発を勉強しています (初心者)。試してみたコードがいくつか見つかりましたが、なぜ動作するのかよくわかりません。ライブラリのソース コードとドキュメントを調べましたが、漠然としたアイデアしかなく、まだうまくいきません。以下のコードに注意してください。

package main

import (
    "fmt"
    "net/http"
)

type foo int

func (m foo) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintln(w, "Some text")
}

func main() {
    var bar foo
    http.ListenAndServe(":8080", bar)
}

私が理解しているところによると、*を追加するとServeHTTP(w http.ResponseWriter, rhttp.リクエスト)関数メソッドとして、ハンドラインターフェース(私が正しく言っているならば)そして今フー型ハンドラー私も理解していますhttp.ListenAndServeハンドラ型の入力を受け取るので、変数はバーが登場します。コードを実行してブラウザで localhost:8080 にアクセスすると、「Some Text」が表示されます。

質問:

これは具体的にどのように機能するのでしょうか? ServeHTTP 関数にはどのようにしてアクセスするのでしょうか?

ライブラリのソース コードを確認してみましたが、ServeHTTP がどのように動作するのか正確にはわかりませんでした。次の 2 つのコード (該当するかどうかはわかりません) を見つけましたが、これは関数を実装しているという印象を与えるものの、説明が必要です。

// The HandlerFunc type is an adapter to allow the use of
// ordinary functions as HTTP handlers. If f is a function
// with the appropriate signature, HandlerFunc(f) is a
// Handler that calls f.
type HandlerFunc func(ResponseWriter, *Request)

// ServeHTTP calls f(w, r).
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
    f(w, r)
}

型名の後に関数がある HandlerFunc を使用した上記のような型宣言は見たことがありません。メソッドの宣言方法も見たことがありますが、上記のコードで何が起こっているのかわかりません。

ベストアンサー1

これは具体的にどのように機能するのでしょうか? ServeHTTP 関数にはどのようにしてアクセスするのでしょうか?

この質問に答えるには、どのようにhttp.ListenAndServe機能するかを確認する必要があります。

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

ここでは、指定されたアドレスとハンドラーを使用してサーバーを作成し、ListenAndServer メソッドを呼び出します。それでは、そこを見てみましょう。

func (srv *Server) ListenAndServe() error {
    addr := srv.Addr
    if addr == "" {
        addr = ":http"
    }
    ln, err := net.Listen("tcp", addr)
    if err != nil {
        return err
    }
    return srv.Serve(tcpKeepAliveListener{ln.(*net.TCPListener)})
}

このメソッドは、指定されたアドレスでリッスンを開始し、新しく作成されたリスナーを使用して Server メソッドを呼び出すだけなので、その手順を追ってみましょう。

func (srv *Server) Serve(l net.Listener) error {
    defer l.Close()
    
    ...
    
    for {
        rw, e := l.Accept()

        ...

        c := srv.newConn(rw)
        c.setState(c.rwc, StateNew) // before Serve can return
        go c.serve(ctx)
    }
}

Serve メソッドから、これが新しい接続を受け入れ、独自の goroutine で処理を開始するポイントであることがわかります。

// Serve a new connection.
func (c *conn) serve(ctx context.Context) {
    ...
    for {
        w, err := c.readRequest(ctx)
        ...
        serverHandler{c.server}.ServeHTTP(w, w.req)
        ...
    }
}

ここで、最終的に ServeHTTP メソッドを呼び出しますが、これはまだその関数の実装ではなく、標準ライブラリからのものであることがわかります。そこで、serverHandler 構造体に何が含まれているかを見てみましょう。

// 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
    }
    if req.RequestURI == "*" && req.Method == "OPTIONS" {
        handler = globalOptionsHandler{}
    }
    handler.ServeHTTP(rw, req)
}

最終的に次のようになります。Handler を指定しなかった場合は、DefaultServeMux が使用されます。ただし、foo ハンドラーを指定したので、foo からの ServeHTTP が呼び出されます。

以上です。これらはすべて@でご覧いただけます。サーバー.go

おすすめ記事