Как использовать Context.Request.Body и сохранить его?

Я пытаюсь написать промежуточное ПО, в котором я буду выполнять проверку схемы 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": "[email protected]",
    "password": "123"
} 

I am a middleware for json schema validation
body is: 

Ожидаемый результат:

{
    "email": "[email protected]",
    "password": "123"
} 
I am a middleware for json schema validation
body is: {
    "email": "[email protected]",
    "password": "123"
}

person Sanath Ballal    schedule 14.08.2015    source источник
comment
play.golang.org/p/N_553jVAIX показывает несколько вариантов дублирования io.ReadCloser в обработчике HTTP. . Чтобы выбрать между ними, потребуются подробности того, что происходит с телом, и ожидаемый размер.   -  person Dave C    schedule 16.08.2015


Ответы (3)


То, что сказал Теллимист, но попросту.

Вам нужно «поймать и восстановить» Тело. Body - это буфер, а это значит, что как только вы его прочтете, он исчезнет. Итак, если вы поймаете его и «положите обратно», вы снова сможете получить к нему доступ.

Отметьте этот ответ, я думаю, это то, что вы ищете: https://stackoverflow.com/a/47295689/3521313

person transistor    schedule 15.11.2017

Вы можете скопировать req.Body внутри своего промежуточного программного обеспечения. Ознакомьтесь с io.TeeReader + bytes.Buffer.

Насколько я знаю, вы не можете напрямую скопировать io.Reader, поэтому вы должны скопировать его, пока читаете, а затем назначить скопированный обратно c.Request.Body, чтобы иметь возможность использовать его для c.Bind

Я не уверен, но, возможно, это поможет Полегче.

person Thellimist    schedule 15.08.2015

Если вы хотите использовать содержимое тела несколько раз, и вы также используете gin-gonic, я думаю, что функция ShouldBindBodyWith - это то, что вы ищете.

ShouldBindBodyWith аналогичен ShouldBindWith, но сохраняет тело запроса в контексте и повторно использует его при повторном вызове.

ПРИМЕЧАНИЕ. Этот метод считывает тело перед привязкой. Поэтому вы должны использовать ShouldBindWith для повышения производительности, если вам нужно вызвать только один раз.

Использованная литература:

person Noel Ruault    schedule 29.05.2019