Gin - Go lang How to use Context.Request.Body and

2019-07-14 07:04发布

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"
}

标签: go go-gin
3条回答
戒情不戒烟
2楼-- · 2019-07-14 07:35

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:

查看更多
干净又极端
3楼-- · 2019-07-14 07:48

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

查看更多
我只想做你的唯一
4楼-- · 2019-07-14 07:54

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.

查看更多
登录 后发表回答