gin/golang - 请求体为空

9

我是Go和Gin的新手,我在打印出完整请求体方面遇到了问题。

我想要能够读取来自第三方POST的请求体,但我得到的是空的请求体。

curl -u dumbuser:dumbuserpassword -H "Content-Type: application/json" -X POST --data '{"events": "3"}' http://localhost:8080/events

以下是我的整个代码。欢迎提出任何建议!

package main

import (
  "net/http"
  "fmt"
  "github.com/gin-gonic/gin"
)

func main() {
  router := gin.Default()
  authorized := router.Group("/", gin.BasicAuth(gin.Accounts{
     "dumbuser": "dumbuserpassword",
  }))
  authorized.POST("/events", events)
  router.Run(":8080")
}

func events(c *gin.Context) {
  fmt.Printf("%s", c.Request.Body)
  c.JSON(http.StatusOK, c)
}
1个回答

32
问题在于您正在打印的字符串值,它是接口类型。

为了满足您自己的要求,确实包含您想要的正文,您可以将值从读取为字符串,然后打印出来。这仅用于您的学习过程!

学习代码:

func events(c *gin.Context) {
        x, _ := ioutil.ReadAll(c.Request.Body)
        fmt.Printf("%s", string(x))
        c.JSON(http.StatusOK, c)
}

然而,这不是访问请求正文的正确方式。通过使用绑定(binding),让gin为你解析请求的正文。

更正式的代码:

type E struct {
        Events string
}

func events(c *gin.Context) {
        data := &E{}
        c.Bind(data)
        fmt.Println(data)
        c.JSON(http.StatusOK, c)
}

这是一种更正确的访问请求体数据的方法,因为它已经被解析出来了。需要注意的是,如果像我们在学习步骤中上面所做的那样首先读取了请求体,那么c.Request.Body将会被清空,因此Gin将无法读取到任何请求体。

错误代码:

func events(c *gin.Context) {
    x, _ := ioutil.ReadAll(c.Request.Body)
    fmt.Printf("%s", string(x))
    data := &E{}
    c.Bind(data) // data is left unchanged because c.Request.Body has been used up.
    fmt.Println(data)
    c.JSON(http.StatusOK, c)
}

你可能也好奇为什么从此端点返回的JSON显示为空的 Request.Body。这是因为同样的原因。JSON编组方法无法序列化ReadCloser,因此显示为空。


谢谢,Danver,你真的帮了我很多,也很有教育意义。 - Leon Hu
2
如果绑定失败怎么办?由于 Reader 已被清空,那么数据是否会丢失? - Sean Lindo
我也想知道Sean的问题的答案。 - winduptoy
Gin确实会返回一个错误,以便让您检测绑定失败的情况。但是据我所知,在那个时候为时已晚,您格式不正确的数据已经丢失了。如果存储不当的数据是必需的,则可以尝试首先复制Req.Body,但然后您将不得不执行调用以自己解析Json,而不是使用gin。这可能值得在gin项目上提出一张票。 - Danver Braganza

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