异常处理与错误码
# 异常处理与错误码
# 目的
让读者在调用 API 或排查页面失败时,能根据 HTTP 状态、code 和公开 message 决定是改请求、刷新登录还是停止重试。成功时 code 为 0;失败时响应仍带 requestId,但不包含内部堆栈或敏感字段。
# 前置条件
本页描述统一 JSON 出口;生产业务 JSON 在 JWE 内,须先解密再读 code。身份相关请求须带精确 Origin 与 X-App-Request,否则可能先收到 403004 而不是下表中的业务码。
HTTP 状态表示传输结果,code 表示稳定的业务原因。前端优先展示 fieldErrors 中的字段说明;没有字段提示时再展示目录固定 message。日志和排查使用 requestId。内部 Oops 错误链、堆栈和属性只留在服务端。
业务码、HTTP 状态和公开中文只登记在 fago/fago-server/modules/fago-contracts/errors.go。调用点传入该目录中的业务码,并另写固定英文诊断;公开中文和 HTTP 状态不要在各模块再写一份。新增一个码时,要同时改这份目录和下面的表。未登记的数字一律按 500001 返回。响应不采用调用点或依赖库自行填写的 Public 文本。细粒度原因放在服务端英文诊断和属性里,不另造一套 slug 码。
| HTTP | code | 公开提示 | 调用方 |
|---|---|---|---|
| 400 | 400001 | 请求格式不正确 | 修正请求 |
| 400 | 400002 | 字段校验失败 | 按 fieldErrors 改表单 |
| 401 | 401001 | 访问凭证已过期 | 受保护接口只刷新一次并重试原请求 |
| 401 | 401002 | 会话已失效,请重新登录 | 重新登录,不要循环刷新 |
| 401 | 401003 | 账号或密码错误 | 重新登录 |
| 403 | 403001 | 没有操作权限 | 不要刷新 token |
| 403 | 403002 | 租户不可用 | 不要刷新 token |
| 403 | 403003 | 请先修改密码 | 只走改密,不要当成 access 过期 |
| 403 | 403004 | 请求来源校验失败 | 核对精确 Origin |
| 403 | 403005 | 操作者身份验证失败 | 保留目标数据,重新输入操作者口令 |
| 404 | 404001 | 资源不存在或不可见 | 不要据此判断记录是否存在 |
| 409 | 409001 | 记录已变更,请重试 | 刷新后再提交,不要覆盖 |
| 409 | 409002 | 编码已存在 | 更换编码 |
| 409 | 409003 | 当前状态不允许此操作 | 先解除引用或改变状态 |
| 409 | 409004 | 部门层级不合法 | 调整父级或规模 |
| 409 | 409005 | 租户用户配额已满 | 减少用户或提高套餐配额,不要原样重试创建 |
| 429 | 429001 | 请求过于频繁,请稍后重试 | 遵守 Retry-After,不要无限重试 |
| 500 | 500001 | 服务内部错误 | 展示 requestId |
| 503 | 503001 | 依赖服务暂时不可用 | 展示 requestId;这是依赖失败,不是业务拒绝 |
写请求不自动重试。网络结果不确定时,先查询当前状态,再决定是否再次提交。生产环境下,成功、拒绝和业务冲突的 JSON 都在加密响应里,解密之后才看 code。
# 响应示例
开发/测试下,业务成功与 access 过期分别如下(字段名与 接口与错误码 一致):
{
"code": 0,
"data": {},
"message": "ok",
"requestId": "req_example"
}
{
"code": 401001,
"message": "访问凭证已过期",
"requestId": "req_example"
}
受保护接口在收到 401001 时,客户端最多自动刷新一次并重试原请求;401002 必须重新登录,不能循环刷新。版本冲突示例:
{
"code": 409001,
"message": "记录已变更,请重试",
"requestId": "req_example"
}
字段校验失败时,顶层 message 仍为目录固定文案,具体改法看 fieldErrors(例如改密新口令长度不足):
{
"code": 400002,
"data": null,
"message": "字段校验失败",
"requestId": "req_example",
"fieldErrors": [
{
"field": "newPassword",
"message": "新密码至少需要 8 位"
}
]
}
# 边界
未在 fago-contracts/errors.go 登记的数字一律按 500001 返回。本页不列出每个模块的英文诊断,也不描述 JWE 加解密步骤。
# 关联
加密与脱敏见 日志、脱敏与请求加密。登录相关码的操作上下文见 登录与会话。