http.Handler インターフェース
CoddyのGOジャーニー「オブジェクト指向プログラミング」セクションの一部 — レッスン 77/107。
http.Handler インターフェースは、Goのウェブサーバーアーキテクチャの基盤です。これはHTTPリクエストがどのように処理されるかを定義しており、これを実装する任意の型はウェブ要求を処理することができます。
インターフェースは非常にシンプルです:
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}ServeHTTP メソッドを持つ任意の型は、HTTP リクエストを処理できます。以下はカスタムハンドラーの例です:
type GreetHandler struct {
Greeting string
}
func (h GreetHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "%s, visitor!", h.Greeting)
}このハンドラーは、サーバーで直接使用できます:
handler := GreetHandler{Greeting: "Welcome"}
http.Handle("/greet", handler)より単純なケースでは、Goは通常の関数をハンドラーに変換できる型である http.HandlerFunc を提供しています。
func hello(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello!")
}
http.Handle("/hello", http.HandlerFunc(hello))このインターフェースの強力さは、ハンドラーが他のハンドラーをラップできることに気づいたときに明らかになります。これにより、元のハンドラーのロジックを変更することなく、ロギング、認証、またはその他の横断的な関心事を追加するミドルウェアパターンが可能になります。
チャレンジ
簡単Webリクエストがどのように処理されるかをシミュレートする、シンプルなHTTPハンドラーシステムを構築しましょう!この環境では実際のHTTPサーバーを実行できないため、http.Handlerインターフェースを実装するハンドラーを作成し、モックのリクエスト/レスポンスオブジェクトを使用してそれらがどのようにリクエストを処理するかを実演します。
コードは2つのファイルに分けて構成します:
handlers.go: カスタムHTTPハンドラーを定義します。HTTPレスポンスに書き込まれる内容をキャプチャする
MockResponseWriter構造体を作成します。これはレスポンスボディを文字列として保存し、データをボディに追加するWrite(data []byte) (int, error)メソッドを実装する必要があります。また、蓄積されたレスポンスを取得するためのBody() stringメソッドを追加してください。HTTPリクエストをシミュレートするために、
PathとMethodの文字列フィールドを持つMockRequest構造体を作成します。次に、
http.Handlerインターフェースのパターン(*MockResponseWriterと*MockRequestを受け取るServeHTTPメソッドを持つ)を実装する2つのハンドラー構造体を作成します:WelcomeHandler(Messageフィールドを持つ) - メッセージの後にリクエストパスを続けて書き込みます。MethodHandler- リクエストメソッドに基づいて異なるレスポンスを書き込みます:GETの場合は"Fetching data"、POSTの場合は"Creating resource"、それ以外の場合は"Method not supported"とします。
main.go: ハンドラーを通じてリクエストを処理します。ハンドラータイプ(
welcomeまたはmethod)を読み取り、次にリクエストの詳細を読み取ります。welcomeハンドラーの場合は、ウェルカムメッセージも読み取ります。適切なハンドラーを作成し、モックリクエストを構築して、
ServeHTTPを呼び出して処理します。レスポンスボディをプリントしてください。
以下の入力が提供されます:
- 1行目:ハンドラータイプ(
welcomeまたはmethod) - 2行目:リクエストパス
- 3行目:リクエストメソッド
- 4行目(welcomeの場合のみ):ウェルカムメッセージ
例えば、以下が与えられた場合:
welcome
/home
GET
Hello from出力は以下のようになります:
Hello from /homeまた、以下が与えられた場合:
method
/api/users
POST出力は以下のようになります:
Creating resourceまた、以下が与えられた場合:
method
/api/data
GET出力は以下のようになります:
Fetching dataまた、以下が与えられた場合:
method
/api/items
DELETE出力は以下のようになります:
Method not supportedこのチャレンジは、http.Handlerインターフェースの核心的な概念、つまりServeHTTPメソッドを持つ任意の型がリクエストを処理できることを示しています。実際のアプリケーションでは、http.ResponseWriterと*http.RequestはGoの標準ライブラリから提供されますが、ハンドラーを実装するパターンは全く同じです。
チートシート
http.Handler インターフェースは、Goのウェブサーバーアーキテクチャの基盤です:
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}ServeHTTP メソッドを持つ任意の型は、HTTPリクエストを処理できます:
type GreetHandler struct {
Greeting string
}
func (h GreetHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "%s, visitor!", h.Greeting)
}サーバーにハンドラーを登録します:
handler := GreetHandler{Greeting: "Welcome"}
http.Handle("/greet", handler)より単純なケースでは、http.HandlerFunc を使用して関数をハンドラーに変換します:
func hello(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello!")
}
http.Handle("/hello", http.HandlerFunc(hello))ハンドラーは他のハンドラーをラップすることができ、ロギング、認証、またはその他の横断的な関心事のためのミドルウェアパターンを可能にします。
自分で試してみよう
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
scanner := bufio.NewScanner(os.Stdin)
// ハンドラーのタイプを読み込む
scanner.Scan()
handlerType := scanner.Text()
// リクエストパスを読み込む
scanner.Scan()
path := scanner.Text()
// リクエストメソッドを読み込む
scanner.Scan()
method := scanner.Text()
// モックリクエストを作成
request := &MockRequest{
Path: path,
Method: method,
}
// モックレスポンスライターを作成
response := &MockResponseWriter{}
// TODO: handlerTypeに基づいて、適切なハンドラーを作成する
// handlerTypeが "welcome" の場合は、ウェルカムメッセージを読み込んで WelcomeHandler を作成する
// handlerTypeが "method" の場合は、MethodHandler を作成する
// ハンドラーの ServeHTTP を response と request を引数にして呼び出す
if handlerType == "welcome" {
scanner.Scan()
message := scanner.Text()
// TODO: メッセージを使用して WelcomeHandler を作成し、ServeHTTP を呼び出す
_ = message // 実装時にこの行を削除してください
} else if handlerType == "method" {
// TODO: MethodHandler を作成し、ServeHTTP を呼び出す
}
// レスポンスボディを出力
fmt.Println(response.Body())
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
1Go オブジェクト指向の基礎
外部ファイルGo ワークスペースとモジュールパッケージとインポート公開された名前と非公開の名前Go におけるオブジェクト指向入門クラスとしての構造体構造体へのメソッド定義ポインタレシーバと値レシーバ構造体の初期化コンストラクタ関数まとめ:簡易計算機8エラー処理とOOP
error インターフェースカスタムエラー型エラーラッピング (fmt.Errorf)センチネルエラーerrors.Is() と errors.As()Panic、Defer、Recover復習 - ファイルパーサー11標準ライブラリとOOP
io.Reader と io.Writersort.Interfacefmt.Stringer インターフェースencoding/json と構造体http.Handler インターフェースまとめ:REST API モデル