5.16 异常与响应处理
概述
全部响应经 utility/response 统一信封写出;panic 由 Response 中间件 recover 兜底;404/500 状态页输出 JSON 而非 HTML。前端按 code 分流处理(401 跳登录、1 弹 msg)。
统一响应信封(utility/response)
text
成功:{"code":0, "ok":true, "msg":"操作成功", "data":{...}}
失败:{"code":1, "ok":false, "msg":"...", "data":{}}
未认证:HTTP 401 + {"code":401,...}(前端据此跳登录页)写出响应时把 code/body 记入 ctx(respCodeKey/respBodyKey),供 OperationLog 中间件判断成功/失败与记录响应内容。
Fail 映射规则(重要)
text
response.Fail(err):
gerror 码 == 401 → 原样保留 code=401(配合 HTTP 401)
其余 → 一律降级 code=1
含义:consts 里的细分错误码(1001 用户不存在、1003 密码错误……)
主要用于日志与语义区分;前端只看 0/1/401 三个关键值:
0=成功;1=失败(弹 msg);401=未认证(跳登录)业务错误码(consts/biz_err.go)
| 码 | 常量 | 含义 |
|---|---|---|
| 1 | CodeFailed | 通用操作失败 |
| 400 | CodeParamError | 参数校验失败 |
| 401 | CodeUnauthorized | 登录已过期,请重新登录 |
| 403 | CodeForbidden | 没有该操作权限 |
| 429 | CodeTooManyRequests | 请求过于频繁 |
| 500 | CodeServerError | 服务器内部错误 |
| 1001 | — | 用户不存在 |
| 1002 | — | 账号禁用 |
| 1003 | — | 密码错误 |
| 1004 | — | 验证码错误 |
| 1005 | — | 租户过期 |
| 1006 | — | 租户禁用 |
| 1007 | — | 租户用户数上限 |
| 1008 | — | Token 无效 |
| 1009 | — | 记录已存在 |
| 1010 | — | 记录不存在 |
| 1011 | — | 存在下级或关联 |
| 1012 | — | 原密码错误 |
| 1013 | — | 租户不存在 |
| 1014 | — | 记录已被引用 |
| 1015 | — | 演示环境禁止操作 |
(完整对照见 8.2 错误码对照表。)
panic 兜底(Response 中间件)
text
defer recover():
1) 记录堆栈日志(errorStack 控制是否随响应返回)
2) 尚未写出响应 → 输出 500 统一信封(CodeServerError)
3) 已写出响应 → 只记录日志,避免双写
app.errorMsg 控制是否返回详细错误信息(生产建议 false)
server.errorStack 控制响应是否携带错误堆栈(生产建议 false)状态页(404/500)
text
router.go BindStatusHandler:
404 → {"code":1,"msg":"接口不存在: GET /api/xxx"}
500 → {"code":1,"msg":"服务器内部错误"}
非 200 一律输出统一 JSON 信封,不返回 HTML(前后端分离友好)参数校验失败(400)
text
r.Parse(req) 触发 gvalid 标签校验
→ 失败:{"code":400,"msg":"请输入案例名称"}(文案取 v 标签 # 后缀)
→ 业务方法不执行(短路)前端处理策略
text
响应拦截器:
code === 0 → 返回 data
code === 401 → 清令牌 → 尝试 refresh → 失败跳登录页
code === 1 → ElMessage.error(msg)(ResultEnum.ERROR)
其他码 → 按业务需要定制(一般走 1 的统一弹窗即可)排障
| 症状 | 判断 |
|---|---|
| 500 无堆栈 | app.errorMsg/server.errorStack=false(生产预期);看服务端日志 |
| 错误全是 code=1 | 设计如此——细分码在 msg 与服务端日志中区分 |
| 参数错误无具体文案 | v 标签未写 # 自定义文案,用了框架默认提示 |
| 404 返回 HTML | 不应出现——确认经 BindStatusHandler 注册的入口访问(直连静态资源除外) |