杜松子酒-Go lang如何使用Context.Request.Body并保留它?

San*_*lal 3 go go-gin

我正在尝试编写一个中间件,在其中我将对请求主体进行json模式验证。验证之后,我需要再次使用请求正文。但是我不知道该怎么做。我参考了这篇文章, 并找到了一种进入尸体的方法。但是,一旦使用了请求正文,我就需要下一个函数可用。

这是示例代码:

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

}
Run Code Online (Sandbox Code Playgroud)

电流输出:

{
    "email": "test@test.com",
    "password": "123"
} 

I am a middleware for json schema validation
body is: 
Run Code Online (Sandbox Code Playgroud)

预期产量:

{
    "email": "test@test.com",
    "password": "123"
} 
I am a middleware for json schema validation
body is: {
    "email": "test@test.com",
    "password": "123"
}
Run Code Online (Sandbox Code Playgroud)

tra*_*tor 5

Thellimist所说的,但更多的话。

您需要“捕捉并恢复”身体。Body是一个缓冲区,这意味着一旦您阅读它,它就会消失。因此,如果您将其捕获并“放回”,则可以再次访问它。

检查此答案,我认为这是您要寻找的:https : //stackoverflow.com/a/47295689/3521313


The*_*ist 0

您可以在中间件中复制 req.Body 。查看io.TeeReader + bytes.Buffer

据我所知,您不能直接复制 io.Reader,因此您必须在阅读时复制它,然后将复制的内容分配回c.Request.Body才能将其用于c.Bind

我不确定,但这也许可以让事情变得更容易。