Skip to content

错误处理

错误流

service 返回 error,由 handler 统一转成 response.Fail;全局异常兜底在 pkg/middleware

service return err
  → handler _ = c.Error(...) + return
  → middleware.Recover 渲染(HTTP 状态恒 200,body 里 code/Msg)

三条铁律

  1. 错误一律 _ = c.Error(...)return,绝不自己 c.JSON 错误响应——统一由 middleware.Recover 渲染。
  2. 只翻译 service 导出的 哨兵错误errors.Is),其余原样 c.Error(err) 兜底。
  3. 出参只用 response.Ok(...) / response.OkVoid()不写 gin.H

错误类型:errs.ServiceError

go
type ServiceError struct {
    Code   int    // 业务码;0 表示未指定,Recover 回落 500
    Msg    string // 回前端的文案
    Detail string // 只进服务端日志,不回前端
}

构造:errs.New(code, msg, detail)Detailerr.Error() 这类内部细节, 只进日志不回前端

错误码选用

响应体字段 codeHTTP 状态恒为 200,下面列的是 body 里的 code 值,不是 HTTP 状态码):

场景构造响应体 code
参数格式 / 缺失errs.New(response.CodeBadRequest, "参数校验失败", err.Error())400
业务失败(重复、冲突)errs.New(response.CodeFail, "xx失败,yy已存在", "")500
资源不存在errs.New(response.CodeNotFound, "Xxx 不存在", "")404
service 内自定义文案errs.New(0, "内置参数【k】不能删除", "")500 + 该文案

第三个参数 Detail 只进日志不回前端。Code=0middleware.Recover 回落到 CodeFail(500);传非零 Code 时按 response.FailCode 渲染。

哨兵错误翻译示例

go
if err := systemservice.XxxSvcApp.UpdateXxx(c.Request.Context(), &b); err != nil {
    if errors.Is(err, systemservice.ErrXxxKeyExists) {
        _ = c.Error(errs.New(response.CodeFail,
            fmt.Sprintf("修改'%s'失败,key已存在", b.Name), ""))
        return
    }
    if errors.Is(err, systemservice.ErrXxxNotFound) {
        _ = c.Error(errs.New(response.CodeNotFound, "Xxx 不存在", ""))
        return
    }
    _ = c.Error(err)   // 兜底
    return
}
c.JSON(http.StatusOK, response.OkVoid())

详见 pkg 参考 / errs

基于 MIT 协议开源