echo icon indicating copy to clipboard operation
echo copied to clipboard

Cannot read request body after ctx.Bind

Open hayashikun opened this issue 1 year ago • 3 comments

Issue Description

I want to get the request body in httpErrorHandler, but I can't. Once a request body is read by ctx.Bind, it cannot be read afterward.

To read again after reading, the ReaderCloser must be set, but DefaultBinder#BindBody does not do this.

https://github.com/labstack/echo/blob/754479694694f6d0bd280d453c10d63348e4e3b7/middleware/body_dump.go#L72

What is the best way to do this?

Checklist

  • [x] Dependencies installed
  • [x] No typos
  • [x] Searched existing issues and docs

Expected behavior

Can read the request body after ctx.Bind or in httpErrorHandler

Actual behavior

Cannot read the request body after ctx.Bind

Steps to reproduce

Working code to debug

body1 := ctx.Request().Body
buf1, err := io.ReadAll(body1)
if err == nil {
	println("before: " + string(buf1))
}
ctx.Request().Body = io.NopCloser(bytes.NewBuffer(buf1))

bindErr := ctx.Bind(req)

body2 := ctx.Request().Body
buf2, err := io.ReadAll(body2)
if err == nil {
	println("after: " + string(buf2))
}
ctx.Request().Body = io.NopCloser(bytes.NewBuffer(buf2))

return bindErr

When a POST request is sent with {"aaa": "hoge"}, the following log is output

before: {"aaa": "hoge"}
after:

Version/commit

v4.12.0

hayashikun avatar Oct 03 '24 07:10 hayashikun

Yep, there needs to be c.Request().Body = io.NopCloser(bytes.NewBuffer(buf1)) after bindErr := c.Bind(req) as bind will "readAll" that body again and making sure that the reader of the body is reusable is out of scope of its contract.

aldas avatar Oct 03 '24 08:10 aldas

By reassigning ReaderCloser to Body in DefaultBinder#BindBody, Body can be read afterward. If this direction is okay, I will send a PR. What do you think?

hayashikun avatar Oct 04 '24 01:10 hayashikun

In Go, the request body is represented as an io.ReadCloser, which is a stream that can only be read once. Once it’s consumed (e.g., by ctx.Bind()), the body is no longer available for reading. This is a fundamental aspect of streams in Go.

martinyonatann avatar Oct 05 '24 22:10 martinyonatann