问题
后台接收前端的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
方法强制更改响应状态码。
解决
更改 Bind
为 ShouldBind
https://cloud.tencent.com/developer/article/1814919