【问题标题】:golang gin gonic content-type not setting to application/json with c.JSONgolang gin gonic 内容类型未使用 c.JSON 设置为 application/json
【发布时间】:2017-04-27 19:17:19
【问题描述】:

根据official documentation,gin-gonic的c.JSON应该将响应头设置为application/json,但是当我从Postman调用我的API时,响应头设置为text/plain; charset=utf-8

我不明白我错过了什么,知道吗?

文档:

函数 JSON

JSON 将给定的结构作为 JSON 序列化到响应正文中。它 还将 Content-Type 设置为“application/json”。

这是我的代码示例:

func postLogin(c *gin.Context) {
    var credentials DTO.Credentials
    if err := c.BindJSON(&credentials); err == nil {
        c.JSON(buildResponse(services.CheckUserCredentials(credentials)))
    } else {
        var apiErrors = DTO.ApiErrors{}
        for _, v := range err.(validator.ValidationErrors) {
            apiErrors.Errors = append(apiErrors.Errors, DTO.ApiError{Field: v.Field, Message: v.Field + " is " + v.Tag})
        }
        c.JSON(http.StatusBadRequest, apiErrors)
    }
}

编辑

经过调查,log.Println(c.Writer.Header().Get("Content-Type")) 没有打印任何东西,显示内容类型应该是空的。

func writeContentType(w http.ResponseWriter, value []string) {
    header := w.Header()
    log.Println(header.Get("Content-Type")) // <=========== Nothing happen
    if val := header["Content-Type"]; len(val) == 0 {
        header["Content-Type"] = value
    }
}

我真的不想将c.Writer.Header().Set("Content-Type", "application/json") 添加到我架构中的每条路线...

编辑 2

似乎binding:"required" 破坏了 Content-Type 标头

type Credentials struct {
    Email         string        `json:"email" binding:"required"`
    Password      string        `json:"password" binding:"required"`
}

【问题讨论】:

    标签: json go


    【解决方案1】:

    使用c.ShouldBindJSON(&amp;credentials) 而不是c.BindJSON。

    Gin README.md - Model binding and validation

    这些方法在后台使用 MustBindWith。如果有绑定 错误,请求被 c.AbortWithError(400, 错误).SetType(ErrorTypeBind)。这会将响应状态代码设置为 400 并且 Content-Type 标头设置为 text/plain;字符集=utf-8。

    【讨论】:

    • 为什么?你能解释一下为什么这是首选,而不是仅仅建议人们遵循这个吗?
    • 这个答案与问题无关。问题是关于在c.JSON的响应上设置Content-Type
    【解决方案2】:

    如果您希望所有请求都是 JSON,请添加一个中间件。

    func JSONMiddleware() gin.HandlerFunc {
        return func(c *gin.Context) {
            c.Writer.Header().Set("Content-Type", "application/json")
            c.Next()
        }
    }
    

    在你的路由器上添加

    router.Use(JSONMiddleware())
    

    【讨论】:

      【解决方案3】:

      看了源码,好像Content-Type已经设置了就不会写头了。

      c.JSON 调用this function 调用以下代码:

      func writeContentType(w http.ResponseWriter, value []string) {
          header := w.Header()
          if val := header["Content-Type"]; len(val) == 0 {
              header["Content-Type"] = value
          }
      }
      

      因此您的Content-Type 必须设置在其他位置。

      【讨论】:

      • 不错的收获!所以无论如何我可以让它“取消设置”,让它根据需要自动设置?
      • 首先我会验证您的标题是否已设置。但是您可以将标题设置为nil,如下所示:w.Header() = nil。这似乎很愚蠢,但我想这是 API 的选择。
      • c.Writer.Header().Write(nil) 不要改变结果,是的,它很傻:(
      • 啊,我写错了。您需要删除 Content-Type 标头。你可以这样做:w.Header().Del("Content-Type").
      • 是的,我试过了,不工作,唯一的方法是写 c.Writer.Header().Set("Content-Type", "application/json") 但那太丑了做添加到处都是,我很沮丧^^
      猜你喜欢
      • 2020-04-14
      • 1970-01-01
      • 2015-08-22
      • 1970-01-01
      • 1970-01-01
      • 2012-02-28
      • 1970-01-01
      • 2019-03-01
      • 1970-01-01
      相关资源
      最近更新 更多