6

我正在尝试编写一个中间件,我将在其中对请求正文进行 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")
}

电流输出:

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

I am a middleware for json schema validation
body is: 

预期输出:

{
    "email": "test@test.com",
    "password": "123"
} 
I am a middleware for json schema validation
body is: {
    "email": "test@test.com",
    "password": "123"
}
4

3 回答 3

7

Thellimist 所说的,但更多的话。

你需要“抓住并恢复”身体。Body 是一个缓冲区,这意味着一旦你阅读它,它就消失了。所以,如果你抓住它并“放回去”,你就可以再次访问它。

检查这个答案,我认为这就是你要找的: https ://stackoverflow.com/a/47295689/3521313

于 2017-11-15T19:21:50.167 回答
0

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

据我所知,您不能直接复制 io.Reader ,因此您必须在阅读时复制它,然后将复制的一个分配回以便c.Request.Body能够使用它c.Bind

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

于 2015-08-15T12:42:30.567 回答
0

如果你想多次使用 body 内容并且你也在使用 gin-gonic,我认为这个ShouldBindBodyWith功能就是你要找的。

ShouldBindBodyWith 与 ShouldBindWith 类似,但它将请求体存储到上下文中,并在再次调用时重用。

注意:此方法在绑定之前读取正文。因此,如果您只需要调用一次,则应该使用 ShouldBindWith 以获得更好的性能。

参考:

于 2019-05-29T00:42:59.043 回答