ミドルウェアでリクエストボディを読み取ったあと、次のハンドラでもリクエストボディを読み取れるようにしておきたい場合があります。
一旦iouti.ReadAll()
で取得したリクエストボディの中身(以下の例では変数buf
)を元にioutil.NopColoser()
でio.ReadCloser
を作って、Request.Body
にセットしなおすことで、次のハンドラでも読み取れるようになります。
func middleware(h http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
...
buf, err := ioutil.ReadAll(r.Body)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
return
}
r.Body = ioutil.NopCloser(bytes.NewBuffer(buf))
...
h(w, r)
return
}
}
ioutil.NopColoser
は次のようにClose()
を呼び出しても何もしない実装になっています。
type nopCloser struct {
io.Reader
}
func (nopCloser) Close() error { return nil }
// NopCloser returns a ReadCloser with a no-op Close method wrapping
// the provided Reader r.
func NopCloser(r io.Reader) io.ReadCloser {
return nopCloser{r}
}
labstack/echo
のmiddlewareパッケージにあるBodyDumpWithConfig
でも同じようなことしている箇所がありました。
https://github.com/labstack/echo/blob/6d9e043284aea2d07f5fcaf0d3a424eb7d9f6109/middleware/body_dump.go#L68-L73