在beego中通过定义response结构体和basecontroller封装success/error方法,统一返回code/msg/data格式json响应,避免重复代码和前端解析问题。

在Beego项目中统一返回code/msg/data结构的JSON响应,避免每个控制器重复写状态码和字段拼装,防止前端解析失败或字段名不一致。
定义全局响应结构体
在controllers目录下新建response.go文件,声明标准结构体:
type Response struct {
Code int `json:"code"`
Msg string `json:"msg"`
Data interface{} `json:"data,omitempty"`
}
【字段首字母必须大写】否则JSON序列化后字段为空——Go语言规定小写字段不可导出,ServeJSON无法访问。
创建 BaseController 并封装 Success/Error 方法
新建base_controller.go,让所有业务控制器继承它:
type BaseController struct {
beego.Controller
}
func (c *BaseController) Success(data interface{}) {
c.Data["json"] = Response{Code: 200, Msg: "success", Data: data}
c.ServeJSON()
c.StopRun()
}
func (c *BaseController) Error(code int, msg string, data interface{}) {
c.Data["json"] = Response{Code: code, Msg: msg, Data: data}
c.ServeJSON()
c.StopRun()
}
注意:c.StopRun()必须加,否则后续代码仍会执行,可能触发重复响应 panic。
在业务控制器中调用封装方法
以CategoryController为例:
type CategoryController struct {
BaseController
}
func (c *CategoryController) List() {
list, err := models.GetCategoryList()
if err != nil {
c.Error(500, "获取分类列表失败", nil)
return
}
c.Success(list)
}
这一步操作起来很简单,直接替换原来的手动赋值+ServeJSON组合,无需改动路由注册逻辑。
按 HTTP 状态码自动映射响应头(可选增强)
方法一:重写 ServeJSON 行为
在 BaseController 中覆盖 ServeJSON:
func (c *BaseController) ServeJSON() {
if code, ok := c.Data["json"].(Response); ok {
if code.Code >= 400 && code.Code c.Ctx.ResponseWriter.WriteHeader(code.Code)
}
}
c.Controller.ServeJSON()
}
方法二:显式设置状态码(推荐)
修改 Success/Error 方法,在 ServeJSON 前手动写入状态码:
c.Ctx.ResponseWriter.WriteHeader(http.StatusOK)
c.Data["json"] = Response{...}
c.ServeJSON()
不这样做会导致 500 错误时响应体是 JSON 但 HTTP 状态码仍是 200,前端 axios/fetch 的 catch 分支收不到错误响应。











