Skip to content

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) ​

码常量含义
1CodeFailed通用操作失败
400CodeParamError参数校验失败
401CodeUnauthorized登录已过期,请重新登录
403CodeForbidden没有该操作权限
429CodeTooManyRequests请求过于频繁
500CodeServerError服务器内部错误
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 注册的入口访问(直连静态资源除外)

小蚂蚁云团队 · 提供技术支持