获取Go Gin请求体中的JSON数据

33

我使用Postman来发送数据,在请求体(Request Body)中,我放置了一些简单的Json。

{
    "order":"1",
    "Name":"ts1"
}

我需要将数据转换为JSON格式,我尝试像下面这样操作,但没有得到想要的JSON结果,请问是否有遗漏的部分?

router.POST("/user", func(c *gin.Context) {
        var f interface{}
        //value, _ := c.Request.GetBody()
        //fmt.Print(value)

        err2 := c.ShouldBindJSON(&f)
        if err2 == nil {
            err = client.Set("id", f, 0).Err()
            if err != nil {
                panic(err)
            }

        }

f不是一个json格式,我收到了错误提示,请问有什么办法可以解决吗? 错误信息如下:

redis: can't marshal map[string]interface {} (implement encoding.BinaryMarshaler)

我使用 https://github.com/go-redis/redis#quickstart

如果我删除正文并使用类似于以下的硬编码代码,我可以设置数据,它可行

json, err := json.Marshal(Orders{
    order:   "1",
    Name: "tst",
})

client.Set("id", json, 0).Err()

你遇到了什么错误? - Charlie Tumahai
@CeriseLimón - 请查看我的更新。 - Beno Odr
看起来你的目标是将发布的JSON文档存储到Redis中。如果是这样,请将请求体读入[]byte并将其存储在Redis中,不要将JSON解码为Go值。 - Charlie Tumahai
@CeriseLimón - 你是指像这样的代码吗:buf := make([]byte, 1024) value, _ := c.Request.Body.Read(buf) 然后将这个值用于 Redis? - Beno Odr
请参考hmm的答案来完成此操作。您在评论中提供的代码不能保证读取整个请求体,包括请求体长度小于1024的情况。 - Charlie Tumahai
显示剩余3条评论
5个回答

33

如果您只想将请求体JSON作为一个值传递到Redis中,那么您不需要绑定JSON到一个值。直接从请求体中读取原始JSON并将其传递即可:

jsonData, err := ioutil.ReadAll(c.Request.Body)
if err != nil {
    // Handle error
}
err = client.Set("id", jsonData, 0).Err()

1
我已经尝试过了,但是没有任何显示。c.Request.Body为空。 - Frank AK
我也收到了空响应。 - Hari Prasanth
5
自Go 1.16起,应使用io.ReadAll代替ioutil.ReadAll https://pkg.go.dev/io/ioutil。 - Big_Boulard
3
如果您需要两次读取正文,则此方法将无法正常工作。 - Logan

29

让我们用一个例子来说明。假设您的请求主体中有一个用户电子邮件,就像这样:

{ email: "test@test.com" }

现在您想在后端获取此电子邮件。首先,定义一个如下的结构体:

    type EmailRequestBody struct {
    Email string
    }

现在,您可以轻松地将请求体中的电子邮件值绑定到您定义的结构体中:首先,为您的结构体定义一个变量,然后绑定该值:

现在,您可以轻松地将请求体中的电子邮件值绑定到您定义的结构体中:首先,为您的结构体定义一个变量,然后绑定该值:

func ExampleFunction(c *gin.Context) {

var requestBody EmailRequestBody

   if err := c.BindJSON(&requestBody); err != nil {
       // DO SOMETHING WITH THE ERROR
   }

  fmt.Println(requestBody.Email)
}

你可以轻松地访问电子邮件值并将其打印出来,或者按需执行其他操作:

fmt.Println(requestBody.Email)

11

或者您可以使用GetRawData()函数:

jsonData, err := c.GetRawData()

if err != nil{
   //Handle Error
}

err = client.Set("id", jsonData, 0).Err()

6
如果想要像其他框架(如Nodejs中的express)一样获取JSON主体,则可以执行以下操作。
bodyAsByteArray, _ := ioutil.ReadAll(c.Request.Body)
jsonBody := string(bodyAsByteArray)

1
请务必处理ioutil.ReadAll的错误。应避免使用下划线,因为bodyAsByteArray可能为空,服务器可能会出现恐慌。 - Musab Gultekin

1
非常好的回答,@arifur Rahman,但是如果你想从请求体中访问JSON值呢? 这是解决方案:
bodyAsByteArray, _ := ioutil.ReadAll(c.Request.Body) 
jsonBody := string(bodyAsByteArray)

所以,上述行将会将您的请求体转换为字符串。您可以直接打印字符串,但无法访问JSON值,因为它是一个字符串。因此,为了访问JSON值,您需要进行解析。
请按照以下代码进行操作:
bodyAsByteArray, _ := ioutil.ReadAll(c.Request.Body)
jsonMap := make(map[string]interface{})
json.Unmarshal(bodyAsByteArray, &jsonMap)

如果您的请求体如下所示:
``` { "order": "1", "Name": "ts1" } ```
那么,
1. 在第一种情况下,您无法使用`jsonBody["order"]`访问它。 2. 在第二种情况下,您可以使用`jsonMap["order"]`访问它。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接