[解決済み] Golang がリクエストボディを複数回読み込む [duplicate].
質問
logginMiddlewareを自作しています。基本的には、リクエストとレスポンスのbodyを記録する必要があります。問題は、bodyを読み込む際に、bodyが空になってしまい、2回読み込むことができないことです。 これは、ReadCloserタイプであるために起こることだと理解しています。ボディを最初に巻き戻す方法はありますか?
解決方法を教えてください。
リクエストボディの検査とモッキング
最初にボディを読んだら、それを保存しておく必要があります。そうすれば、一度読み終えたら、新しい
io.ReadCloser
を元のデータから構築されたリクエストボディとして設定します。そのため、チェーンを進めると、次のハンドラは同じボディを読み取ることができます。
一つの選択肢は、ボディ全体を
ioutil.ReadAll()
を使って、本文をバイト単位で読むことです。
を使うことができます。
bytes.NewBuffer()
を取得するために
io.Reader
をバイトスライスから取得します。
最後に足りない部分は
io.Reader
であり
io.ReadCloser
というのも
bytes.Buffer
には
Close()
メソッドがありません。このため
ioutil.NopCloser()
で囲みます。
io.Reader
をラップし
io.ReadCloser
で、その追加された
Close()
メソッドは no-op (何もしない) になります。
new"ボディを作成するために使用するバイトスライスの内容を変更することもできることに注意してください。あなたはそれを完全に制御することができます。
しかし、データのみを変更した場合、content-length や checksums のような他の HTTP フィールドが無効になる可能性があるため、注意が必要です。後続のハンドラーがそれらをチェックする場合、それらも修正する必要があります。
レスポンスボディの検査/修正
レスポンスボディも読みたい場合は、レスポンスボディにある
http.ResponseWriter
をラップし、ラッパーをチェーンで渡す必要があります。このラッパーは、送信されたデータをキャッシュすることができ、 後から、あるいはその場で(後続のハンドラが書き込む際に)検査することができます。
ここでは、単純な
ResponseWriter
ラッパーです。これはデータをキャッシュするだけなので、後続のハンドラが戻った後でも利用可能です。
type MyResponseWriter struct {
http.ResponseWriter
buf *bytes.Buffer
}
func (mrw *MyResponseWriter) Write(p []byte) (int, error) {
return mrw.buf.Write(p)
}
なお
MyResponseWriter.Write()
はデータをバッファに書き込むだけです。また、オンザフライで検査することもできます (
Write()
メソッドで)その場で検査し、データをすぐにラップされた/埋め込まれた
ResponseWriter
. データを修正することもできます。あなたは完全にコントロールすることができます。
しかし、後続のハンドラはレスポンスデータに関連する HTTP レスポンスヘッダ (長さやチェックサムなど) を送信することがあるので、これにも注意が必要です。
完全な例
これらの部品を組み合わせて、完全な動作例を示します。
func loginmw(handler http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
body, err := ioutil.ReadAll(r.Body)
if err != nil {
log.Printf("Error reading body: %v", err)
http.Error(w, "can't read body", http.StatusBadRequest)
return
}
// Work / inspect body. You may even modify it!
// And now set a new body, which will simulate the same data we read:
r.Body = ioutil.NopCloser(bytes.NewBuffer(body))
// Create a response wrapper:
mrw := &MyResponseWriter{
ResponseWriter: w,
buf: &bytes.Buffer{},
}
// Call next handler, passing the response wrapper:
handler.ServeHTTP(mrw, r)
// Now inspect response, and finally send it out:
// (You can also modify it before sending it out!)
if _, err := io.Copy(w, mrw.buf); err != nil {
log.Printf("Failed to send out response: %v", err)
}
})
}
関連
-
[解決済み] HTTP GET(リクエストボディ付き
-
[解決済み] java.net.URLConnectionを使用してHTTPリクエストを発生させ処理する方法
-
[解決済み] HTTP POSTリクエストでは、どのようにパラメータが送信されるのですか?
-
[解決済み] Access-Control-Allow-Origin複数オリジンのドメイン?
-
[解決済み] node.jsでHTTP POSTリクエストはどのように行われるのですか?
-
[解決済み] PHPでリクエストタイプを検出する(GET, POST, PUT, DELETE)
-
[解決済み] HTTP DELETE リクエストにエンティティボディは許されますか?
-
[解決済み] PHP の cURL は、一度のリクエストでレスポンスヘッダーとボディーの両方を取得できますか?
-
[解決済み] REST APIで "Not Ready Yet, Try Again Later "のHTTPステータスコードを選択するにはどうすればよいですか?[クローズド]。
-
[解決済み] http.NewRequest(...)`を使用して、URLエンコードされたPOSTリクエストを作成する。
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] ERR_INVALID_CHUNKED_ENCODING エラーの修正方法を教えてください。
-
[解決済み] 要求されたURLの長さが、このサーバーの容量制限を超えていませんか?
-
HTTPプロトコルの古典的な面接の質問と回答
-
[解決済み] プロキシが全く応答を受け取らない場合、502 HTTPステータスコードを使用すべきですか?
-
[解決済み] X-REQUEST-ID httpヘッダーとは何ですか?
-
[解決済み] Preflightとredirectを使用したCORSリクエスト: 不許可になりました。回避策は?
-
[解決済み】全てのブラウザで、Webページのキャッシュを制御するには?
-
[解決済み] Go で HTTP レスポンスに文字列としてアクセスする
-
[解決済み] Angular2 http.get()、map()、subscribe()とobservableパターン - 基本的な理解
-
[解決済み] HTTPのPOSTメソッドをキャッシュすることは可能ですか?