【问题标题】:How to use Context.Request.Body and retain it?如何使用 Context.Request.Body 并保留它?
【发布时间】:2015-11-07 15:04:36
【问题描述】:

我正在尝试编写一个中间件,我将在其中对请求正文进行 json 模式验证。验证后,我需要再次使用请求正文。但我无法弄清楚如何做到这一点。我推荐了this post 并找到了进入身体的方法。但是一旦使用了请求正文,我就需要将它用于我的下一个函数。

这里是示例代码:

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

【问题讨论】:

  • play.golang.org/p/N_553jVAIX 展示了在 HTTP 处理程序中复制 io.ReadCloser 的几种变体。需要对身体进行的操作的详细信息以及预期的尺寸在它们之间进行选择。

标签: go go-gin


【解决方案1】:

Thellimist 所说的,但更多的话。

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

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

【讨论】:

    【解决方案2】:

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

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

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

    【讨论】:

      【解决方案3】:

      如果你想多次使用正文内容并且你也在使用 gin-gonic,我认为ShouldBindBodyWith 函数就是你要找的。​​p>

      ShouldBindBodyWith与ShouldBindWith类似,只是将请求体存储到上下文中,再次调用时复用。

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

      参考资料:

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-10-23
        • 1970-01-01
        • 2012-08-12
        • 1970-01-01
        • 1970-01-01
        • 2017-06-14
        相关资源
        最近更新 更多