web-dev-qa-db-ja.com

リクエストの状態を変更せずにhttp.Requestの本文を読み取りますか?

_http.Handler_インターフェイスを実装する型があり、そのServeHTTPメソッドで、着信HTTP要求が検査され、何らかのアクションが実行され、その後、要求がリバースプロキシハンドラーに転送されます(_httputil.NewSingleHostReverseProxy_)。

これは、URLやヘッダーなどの基本的なリクエストプロパティのみを検査している限り、正常に機能します。

たとえば、req.ParseForm()を呼び出してから_req.Form_プロパティを使用して、着信POST要求の本文を検査したい場合、エラーが発生します要求はリバースプロキシに渡されます。

_http: proxy error: http: Request.ContentLength=687 with Body length 0_

HTTPリクエストの本文を見ると_req.Body.Reader_ストリームが排出され、プロキシハンドラーで再度読み取ることができないため、これが起こると思います。

私はio.Copy()bufio.Peek()のようなもので遊んでいますが、実際にはどこにも行きません。

元の要求オブジェクトを元の状態のままにして、HTTPリクエストボディを覗いて(および_req.ParseForm_などの組み込み解析を使用する)方法があります。これにより、リバースプロキシに渡すことができます。 ?

36
Christopher Orr

バッファに読み込んでから、バッファを使用して2つの新しいリーダーをバックアップしてみてください。1つは自分用、もう1つは後続のコンシューマ用です。たとえば、次のコードを変更するとします。

_doStuff(r.Body) // r is an http.Request
_

できること:

_buf, _ := ioutil.ReadAll(r.Body)
rdr1 := ioutil.NopCloser(bytes.NewBuffer(buf))
rdr2 := ioutil.NopCloser(bytes.NewBuffer(buf))

doStuff(rdr1)
r.Body = rdr2 // OK since rdr2 implements the io.ReadCloser interface

// Now the program can continue oblivious to the fact that
// r.Body was ever touched.
_

_*bytes.Buffer_にはClose() errorメソッドがないため、_io.ReadCloser_インターフェイスを実装しないことに注意してください。したがって、_*bytes.Buffer_の呼び出しで_ioutil.NopCloser_値をラップする必要があります。

62
joshlf