错误码设计:框架预留段与业务段划分

面试问法:GoFrame 的错误码体系怎么设计?框架预留了哪些段? 一句话结论:官方约定 <1000 为框架预留段,业务错误码使用 >1000;用 gcode.Code 承载“数字 + 消息 + 详情”,gerror.NewCode 抛出并保留堆栈,统一响应中间件从错误链取码输出 {code,message,data}。业务侧再按模块分段维护常量表,杜绝魔法数字。

段位划分建议

段位归属示例
0成功/无错误(CodeNil)code=0 表示成功
<1000框架预留(内置错误码与常用错误)具体数值以官方 gcode 文档为准
1000+业务通用1001 参数错、1002 未登录
2000+按模块细分用户 2xxx、订单 3xxx…

落地三件套

// 1. 常量包:独立 internal/code 包集中管理
var (
    UserNotExist    = gcode.New(1001, "用户不存在", nil)
    UserPasswordErr = gcode.New(1002, "用户名或密码错误", nil)
    OrderClosed     = gcode.New(2001, "订单已关闭", nil)
)

// 2. 业务层只抛业务码,不拼 HTTP 细节
if user == nil {
    return nil, gerror.NewCode(code.UserNotExist) // gerror 保留堆栈
}
// 3. 统一响应中间件:成功 code=0;失败从错误链取码并记日志
func HandlerResponse(r *ghttp.Request) {
    r.Middleware.Next()
    if r.Response.BufferLength() > 0 { return } // 业务已写回
    if err := r.GetError(); err != nil {
        c := gerror.Code(err) // 链上带业务码则原样透出
        g.Log().Errorf(r.Context(), "%+v", err)
        r.Response.WriteJson(g.Map{"code": c.Code(), "message": err.Error()})
        return
    }
    r.Response.WriteJson(g.Map{"code": 0, "message": "OK", "data": r.GetHandlerResponse()})
}

注意点

  • HTTP 状态码与业务码解耦:业务失败可返回 200 + 非零 code;需要 401/403/404 语义时由中间件按错误码映射状态码。
  • 对客户端展示的 message 要友好、不泄露内部细节;完整堆栈只进服务端日志。
  • 需要错误归类/判断时用 gerror.Is/Equal 或包装错误链,别用字符串匹配。

常见追问

  • 追问:为什么业务码要留到 1000 以上?——避开框架内置码,避免中间件取码时把框架错误与业务错误混淆;数字本身无业务含义,配常量与文档表使用。
  • 追问:错误文案要给前端直接展示吗?——最好分开:给用户看的提示与内部定位信息各存一份(code + userMessage + 日志 detail)。

记忆点

  • 预留段 <1000 归框架、业务 >1000;gcode.New + gerror.NewCode + 统一响应中间件三件套。
  • 内置码的具体数值与常量命名以官方 gcode/gerror 文档为准。
笔记加载中…