英文:
How to use Context.Request.Body and retain it?
问题
我正在尝试编写一个中间件,在其中对请求体进行 JSON Schema 验证。验证完成后,我需要再次使用请求体。但是我无法弄清楚如何实现这一点。我参考了这篇帖子,找到了一种访问请求体的方法。但是一旦请求体被使用,我需要在下一个函数中仍然可以访问它。
以下是示例代码:
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) {
// 在这里进行 JSON Schema 验证
body := c.Request.Body
x, _ := ioutil.ReadAll(body)
fmt.Printf("%s \n", string(x))
fmt.Println("我是用于 JSON Schema 验证的中间件")
c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(x)) // 将请求体重新放回上下文中
c.Next()
return
}
}
type E struct {
Email string
Password string
}
func test(c *gin.Context) {
// data := &E{}
// c.Bind(data)
// fmt.Println(data) // 打印为空,因为 JSON 请求体已经被使用过了
body := c.Request.Body
x, _ := ioutil.ReadAll(body)
fmt.Printf("请求体为: %s \n", string(x))
c.JSON(http.StatusOK, c)
}
func main() {
router := gin.Default()
router.Use(middleware())
router.POST("/test", test)
// 监听并服务
router.Run("127.0.0.1:8080")
}
当前输出:
{
"email": "test@test.com",
"password": "123"
}
我是用于 JSON Schema 验证的中间件
请求体为:
期望输出:
{
"email": "test@test.com",
"password": "123"
}
我是用于 JSON Schema 验证的中间件
请求体为: {
"email": "test@test.com",
"password": "123"
}
希望这可以帮助到你!
英文:
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
得分: 7
Thellimist所说的,但用更多的话来说。
你需要“捕获和恢复”Body。
Body是一个缓冲区,这意味着一旦你读取它,它就会消失。所以,如果你捕获它并“放回去”,你就可以再次访问它。
查看这个答案,我认为这就是你要找的:
https://stackoverflow.com/a/47295689/3521313
英文:
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
得分: 0
你可以在中间件中复制req.Body。可以使用io.TeeReader和bytes.Buffer来实现。根据我所知,你不能直接复制io.Reader,所以你必须在读取时进行复制,然后将复制后的内容赋值给c.Request.Body
,以便在c.Bind
中使用。
我不确定,但也许这个链接可以让事情变得更容易。
英文:
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
得分: 0
如果你想多次使用请求体内容,并且你也在使用gin-gonic,我认为ShouldBindBodyWith
函数是你要找的。
ShouldBindBodyWith
与ShouldBindWith
类似,但它将请求体存储到上下文中,并在再次调用时重用。注意:该方法在绑定之前读取请求体。因此,如果你只需要调用一次,建议使用
ShouldBindWith
以获得更好的性能。
参考资料:
- https://github.com/gin-gonic/gin/issues/1078
- https://godoc.org/github.com/gin-gonic/gin#Context.ShouldBindBodyWith
英文:
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:
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论