沙滩星空的博客沙滩星空的博客

解决Gin框架报错:Headers were already written 请求状态码被覆盖问题

问题

后台接收前端的POST请求,解析请求数据错误,响应状态码被强制更改为 400, 后面更改的 200, 不起效果。

伪代码如下所示:

type JsonObject map[string]interface{}

func ResponseOk(msg string) interface{} {
    return struct {
        Code int
        Msg  string
        Data JsonObject
    }{Msg: msg, Code: 200, Data: JsonObject{}}
}

func ResponseFail(msg string, code int) interface{} {
    return struct {
        Code int
        Msg  string
        Data JsonObject
    }{Msg: msg, Code: code, Data: JsonObject{}}
}

func UpdateItem(c *gin.Context){
    model := map[string]string{}
    err := c.Bind(&model)
    if err != nil {
        c.JSON(200, ResponseFail(msg, 400))
        return
    }
    return c.JSON(200, ResponseOK("修改成功"))
}

预期响应状态码应始终为 200, 但此时却为 400. 控制台打印日志如下:

[GIN-debug] [WARNING] Headers were already written. Wanted to override status code 400 with 200

很明显,代码逻辑大概率没问题,而是框架自作聪明改掉响应状态码。

原因

初步判定,问题应该出现在 err := c.Bind(&model) 这行代码上,追溯代码如下:

func (c *Context) Bind(obj any) error {
    b := binding.Default(c.Request.Method, c.ContentType())
    return c.MustBindWith(obj, b)
}
func (c *Context) MustBindWith(obj any, b binding.Binding) error {
    if err := c.ShouldBindWith(obj, b); err != nil {
        c.AbortWithError(http.StatusBadRequest, err).SetType(ErrorTypeBind) // nolint: errcheck
        return err
    }
    return nil
}

Bind() 方法底层调用 MustBindWith(), 若 MustBindWith() 调用 ShouldBindWith() 方法出现错误,则会调用代码 c.AbortWithError(), 这将强制更改响应状态码,使得接下来对响应状态码的更改操作,都被忽略。

在源码文件中搜索 ShouldBindWith( , 发现有个 ShouldBind 方法,与 MustBindWith 类似,但不会调用 c.AbortWithError 方法强制更改响应状态码。

解决

更改 BindShouldBind


https://cloud.tencent.com/developer/article/1814919

未经允许不得转载:沙滩星空的博客 » 解决Gin框架报错:Headers were already written 请求状态码被覆盖问题

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址