问题
I am trying to write a middleware where I will be doing a json schema validation against the request body. After the validation, I need to use the request body again. But I am not able to figure out how this can be done. I referred this post and found a way to access the body. But once the request body is used, I need that available to my next function.
Here is the sample code:
package main
import (
"fmt"
"io/ioutil"
"net/http"
"github.com/gin-gonic/gin"
//"github.com/xeipuuv/gojsonschema"
)
func middleware() gin.HandlerFunc {
return func(c *gin.Context) {
//Will be doing json schema validation here
body := c.Request.Body
x, _ := ioutil.ReadAll(body)
fmt.Printf("%s \n", string(x))
fmt.Println("I am a middleware for json schema validation")
c.Next()
return
}
}
type E struct {
Email string
Password string
}
func test(c *gin.Context) {
//data := &E{}
//c.Bind(data)
//fmt.Println(data) //prints empty as json body is already used
body := c.Request.Body
x, _ := ioutil.ReadAll(body)
fmt.Printf("body is: %s \n", string(x))
c.JSON(http.StatusOK, c)
}
func main() {
router := gin.Default()
router.Use(middleware())
router.POST("/test", test)
//Listen and serve
router.Run("127.0.0.1:8080")
}
Current output:
{
"email": "test@test.com",
"password": "123"
}
I am a middleware for json schema validation
body is:
Expected output:
{
"email": "test@test.com",
"password": "123"
}
I am a middleware for json schema validation
body is: {
"email": "test@test.com",
"password": "123"
}
回答1:
What Thellimist said, but in more words.
You need to "catch and restore" the Body. The Body is a buffer, that means that once you read it, its gone. So, if you catch it and "put it back", you can access it again.
Check this answer, I think this is what you are looking for: https://stackoverflow.com/a/47295689/3521313
回答2:
You could copy req.Body inside your middleware. Check out io.TeeReader + bytes.Buffer.
As far as I know you can't directly copy an io.Reader so you must copy it while you read it then assign the copied one back to c.Request.Body
to be able to use it for c.Bind
I'm not sure but maybe this can make things easier.
回答3:
If you want to use the body content multiple times and you're also using gin-gonic, I think the ShouldBindBodyWith
function is what you're looking for.
ShouldBindBodyWith is similar with ShouldBindWith, but it stores the request body into the context, and reuse when it is called again.
NOTE: This method reads the body before binding. So you should use ShouldBindWith for better performance if you need to call only once.
References:
- https://github.com/gin-gonic/gin/issues/1078
- https://godoc.org/github.com/gin-gonic/gin#Context.ShouldBindBodyWith
来源:https://stackoverflow.com/questions/32008680/gin-go-lang-how-to-use-context-request-body-and-retain-it