-
Notifications
You must be signed in to change notification settings - Fork 2.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fetching request body in the customErrorHandler middleware #3780
Comments
Hi, thanks for your issue. Yeah this is unfortunate, but I don't know that there's much we can do here. As you say, the body has already been consumed in this case. Note that it shouldn't universally be the case that the body has been consumed, it's likely your specific use case. For example, here the body should still be available: https://github.com/grpc-ecosystem/grpc-gateway/blob/main/runtime/mux.go#L348. If you track down the case that you're hitting, it might be possible to add something that would buffer the request body, but in all honest you're best off doing this at the middleware level where you have access to the request before it's being handled by the gateway runtime. |
We met the same issue and we added one outer wrapper to clone the request body, since the body of the request has been consumed in the customErrorHandler. type logResponseWriter struct {
http.ResponseWriter
statusCode int
}
func (rsp *logResponseWriter) WriteHeader(code int) {
rsp.statusCode = code
rsp.ResponseWriter.WriteHeader(code)
}
func NewLogResponseWriter(w http.ResponseWriter) *logResponseWriter {
return &logResponseWriter{w, http.StatusOK}
}
func LogRequestBody(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
lw := NewLogResponseWriter(w)
body, err := io.ReadAll(r.Body)
if err != nil {
// handle error
}
clonedR := r.Clone(r.Context())
r.Body = io.NopCloser(bytes.NewReader(body))
clonedR.Body = io.NopCloser(bytes.NewReader(body))
h.ServeHTTP(lw, clonedR)
if lw.statusCode != http.StatusOK {
log.Printf("http error %+v, body %+v", w, string(body))
}
})
} mux := runtime.NewServeMux()
return http.ListenAndServe(":8081", LogRequestBody(mux)) |
Maybe one default middleware to clone the request body on the flight, and log this request body when the status code of response is non-OK (200) or leave to the developers to custom this behavior. It just one immature thought. |
I think the workaround you shared here is probably the best solution to this, thank you! |
May I add this workaround to the samples through one PR? @johanbrandhorst |
Of course, please do |
Could you please review this PR? @johanbrandhorst |
🐛 Bug Report
Inside a custom error handler middleware with the
WithErrorHandler
option, I can't access the request body payload (for logging purpose for example). It seems empty (because it was probably already read) How could I do achieve this ?To Reproduce
NewServeMux
function, pass aWithErrorHandler
custom error handler functioncustomErrorHandler
function, try to log the request body. It is empty, probably because it has been read before.Sorry if I misreported it as a bug, I would appreciate some help.
Thanks a lot!
Expected behavior
I would expect to be able to read the request body.
Actual Behavior
I am not able to read the request body.
Your Environment
osx
go 1.21
The text was updated successfully, but these errors were encountered: