私はGolang(初心者)でWeb開発を勉強しています。遊んだコードに出くわしましたが、なぜそれが機能するのかよくわかりません。ライブラリのソースコードとドキュメントを調べましたが、まだ漠然とした考えしかありません。 tクリックします。以下のコードに注意してください。
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、r * http.Request)を追加すると、ハンドラーインターフェイスが呼び出されます(正しく言っている場合)そして今fooはタイプハンドラーでもあります。また、http.ListenAndServeが型ハンドラーの入力を受け取るため、変数barが機能することも理解しています。コードを実行してブラウザでlocalhost:8080に移動すると、「SomeText」が表示されます。
EDIT:インターフェースを実装しますは適切な用語であり、呼び出さないでください。
質問:
これはどのように正確に機能しますか?その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を使用した、上記のような型宣言を見たことがありません。メソッドがどのように宣言されているかも見てきましたが、上記のコードで何が起こっているのかわかりません。
これはどのように正確に機能しますか?その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メソッドから、これが新しい接続を受け入れ、それ自体のゴルーチンで処理を開始するポイントであることがわかります。
// 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)
}
ついに登場です。ハンドラーを指定しなかった場合はDefaultServeMuxが使用されますが、fooハンドラーを指定したため、foogetから呼び出されます。
以上です。これらはすべて server.go から見つけることができます
GoのHTTPサーバーは、リッスンするアドレスとハンドラーを受け取ります。内部的には、TCPリスナーを作成して、指定されたアドレスで接続を受け入れます。要求が着信するたびに、次のようになります。
http.Request
_に解析しますhttp.ResponseWriter
_を作成しますServeHTTP
メソッドを呼び出し、Request
とResponseWriter
を渡して、ハンドラーを呼び出しますハンドラーは、Handler
タイプが行うfoo
インターフェースを満たすものであれば何でもかまいません。
_type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
_
標準ライブラリには、HandlerFunc
(任意のfunc(ResponseWriter, *Request)
を渡してHandler
として使用できる)やServeMux
などの便利な機能も含まれています。多くのHandler
を登録し、着信要求パスに基づいてどの要求を処理するかを選択できます。
Net/httpの関連するタイプは
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
インターフェイスタイプ。このインターフェースを実装する具体的なタイプは、HTTPリクエストを処理するために使用できます。 bar
のタイプはfoo
であり、fooはHandlerインターフェースを実装します。組み込みのHTTPサーバーがリクエストを処理する必要がある場合は、バーのServeHTTPメソッドを呼び出します。
http.Handler
について理解しようとしている人には、これらのブログ投稿を読むことをお勧めします。
Goでのリクエスト処理の要約
HTTPミドルウェアの作成と使用
このコードでの型宣言
type foo int
ハンドラーインターフェイスを実装しています。 ServeHTTP
メソッドを実装するための構造体または任意の型を作成できます。お気に入り
type Foo struct{}
func (m foo) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Some text")
}
ハンドラーインターフェイスまたはその他のインターフェイスを実装する場合インターフェイスで宣言されているすべてのメソッドを、ここでfoo
の型に実装する必要があります。
HandlerFunc
はServeHttp
インターフェースのHandler
メソッドを実装しているため、ハンドラーとしてhttp.ListenAndServe
に渡すことができます。 ServeHttpをラップするミドルウェアを作成するために使用できます。
HanlderFunc
の詳細については、ターミナルでgodocを使用してください
godoc net/http HanlderFunc