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

纵然是瞬间 提交于 2019-12-23 17:10:00

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!