Preface
Recently, I was building go-zero scaffolding and encountered a problem. The original post request was successfully executed. When I added a filter, I would report an error in the request body reading EOF error. I felt a little strange. Why does the logic in the filter affect subsequent requests? Here is a record of the pitfall.
Problem analysis
Let’s first conclusion, this is because the request body in go is a stream, which can only be read once. If you have read the overstream in the filter, then it will not be read in subsequent requests.
The request logic for the example is like this. When the request reaches the background, first pass the filter to check whether the request header carries the token. Otherwise, the request fails. If the request succeeds, the post request logic will continue. This post request and filter are just for examples. The logic is very simple. The logic in the filter is to obtain the token field in the request header. If this field is empty, the request fails. The code example is as follows:
func tokenFilter(next ) { return func(w , r *) { type Request struct { Token string `header:"token"` } var req Request err := (r, &req) if err != nil || == "" { resp, _ := ((, "token required")) (w, , resp) return } next(w, r) } }
According to the official documentation, I used (r, &req) to obtain the request body data in the filter, which caused the subsequent post request logic to read the request body. In other words, this method will consume the data of the request body stream. If you look at the source code, you will find that this method will read the path, form, header, and body data in the request and assign it to our struct:
func Parse(r *, v any) error { kind := ((v)).Kind() if kind != && kind != { if err := ParsePath(r, v); err != nil { return err } if err := ParseForm(r, v); err != nil { return err } if err := ParseHeaders(r, v); err != nil { return err } } if err := ParseJsonBody(r, v); err != nil { return err } if valid, ok := v.(); ok { return () } else if val := (); val != nil { return val.(Validator).Validate(r, v) } return nil }
Continue to view the source code, you will find that the ParseForm method and ParseJsonBody method will consume the data of the requested body stream, and the ParsePath method ParseHeaders method will not. In this filter, we only need to obtain the header data, and the body data needs to be obtained by subsequent logic, so here we need to modify the method of filtering to only obtain the header data. The same is true if the path data is needed. The modified filter:
func tokenFilter(next ) { return func(w , r *) { type Request struct { Token string `header:"token"` } var req Request err := (r, &req) if err != nil || == "" { resp, _ := ((, "token required")) (w, , resp) return } next(w, r) } }
After modification, the subsequent nodes can obtain the request volume data normally.
For the complete sample code, please refer to:igolang
This is the end of this article about the solution to the EOF error of the go-zero read request body. For more related contents to solve the EOF error of the go-zero read request body, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!