跳到主要内容

错误处理

VEF 把传输层 HTTP 行为和业务层结果码区分开来,但最终都会通过统一的 code / message / data 响应包络返回给客户端。

Result 模型总览

VEF 主要使用两种相关但职责不同的结果类型:

类型作用
result.Result最终返回给客户端的响应载荷
result.Error应用代码内部使用的结构化错误对象

result.Result 的形态如下:

{
"code": 0,
"message": "Success",
"data": {}
}

成功响应

成功的 handler 最常见的写法是:

return result.Ok(data).Response(ctx)

result.Ok(...) 支持的形式:

写法含义
result.Ok()不带数据的成功结果
result.Ok(data)带数据的成功结果
result.Ok(result.WithMessage(...))自定义成功消息
result.Ok(data, result.WithMessage(...))同时自定义消息和数据

结构化错误创建

业务失败时,最常见的写法是:

return result.Err(
"user already exists",
result.WithCode(result.ErrCodeRecordAlreadyExists),
)

result.Err(...) 支持的形式:

写法含义
result.Err()默认业务错误
result.Err("message")自定义错误消息
result.Err("message", result.WithCode(...))自定义业务码
result.Err("message", result.WithStatus(...))自定义 HTTP 状态
result.Err("message", result.WithCode(...), result.WithStatus(...))同时覆盖业务码和 HTTP 状态

result.Errf(...) 则是格式化版本。

Result 配置项

可用的 result option:

Option作用对象作用
result.WithCode(code)result.Err(...)设置业务错误码
result.WithStatus(status)result.Err(...)设置 HTTP 状态码
result.WithMessage(message)result.Ok(...)覆盖成功消息
result.WithMessagef(format, ...)result.Ok(...)生成格式化成功消息

内置错误族

VEF 在 result 包里预置了大量常用错误。

认证错误

错误值业务码默认 HTTP 状态
result.ErrUnauthenticatedErrCodeUnauthenticated401
result.ErrTokenExpiredErrCodeTokenExpired401
result.ErrTokenInvalidErrCodeTokenInvalid401
result.ErrTokenNotValidYetErrCodeTokenNotValidYet401
result.ErrTokenInvalidIssuerErrCodeTokenInvalidIssuer401
result.ErrTokenInvalidAudienceErrCodeTokenInvalidAudience401
result.ErrTokenMissingSubjectErrCodeTokenMissingSubject401
result.ErrTokenMissingTokenTypeErrCodeTokenMissingTokenType401

Signature / 外部应用认证错误

错误值业务码默认 HTTP 状态
result.ErrAppIDRequiredErrCodeAppIDRequired401
result.ErrTimestampRequiredErrCodeTimestampRequired401
result.ErrSignatureRequiredErrCodeSignatureRequired401
result.ErrTimestampInvalidErrCodeTimestampInvalid401
result.ErrSignatureExpiredErrCodeSignatureExpired401
result.ErrSignatureInvalidErrCodeSignatureInvalid401
result.ErrExternalAppNotFoundErrCodeExternalAppNotFound401
result.ErrExternalAppDisabledErrCodeExternalAppDisabled401
result.ErrIPNotAllowedErrCodeIPNotAllowed401
result.ErrNonceRequiredErrCodeNonceRequired401
result.ErrNonceInvalidErrCodeNonceInvalid401
result.ErrNonceAlreadyUsedErrCodeNonceAlreadyUsed401
result.ErrAuthHeaderMissingErrCodeAuthHeaderMissing401
result.ErrAuthHeaderInvalidErrCodeAuthHeaderInvalid401

Challenge 流错误

错误值业务码默认 HTTP 状态
result.ErrChallengeTokenInvalidErrCodeChallengeTokenInvalid401
result.ErrChallengeTypeInvalidErrCodeChallengeTypeInvalid400
result.ErrOTPCodeRequiredErrCodeOTPCodeRequired400
result.ErrOTPCodeInvalidErrCodeOTPCodeInvalid401
result.ErrNewPasswordRequiredErrCodeNewPasswordRequired400
result.ErrDepartmentRequiredErrCodeDepartmentRequired400

授权与请求错误

错误值业务码默认 HTTP 状态
result.ErrAccessDeniedErrCodeAccessDenied403
result.ErrTooManyRequestsErrCodeTooManyRequests429
result.ErrRequestTimeoutErrCodeRequestTimeout408
result.ErrUnknownErrCodeUnknown500

业务错误

错误值业务码默认 HTTP 状态
result.ErrRecordNotFoundErrCodeRecordNotFound200
result.ErrRecordAlreadyExistsErrCodeRecordAlreadyExists200
result.ErrForeignKeyViolationErrCodeForeignKeyViolation200
result.ErrDangerousSQLErrCodeDangerousSQL200

错误构造器

以下 helper 会生成具有特定语义的结构化错误:

构造器典型输出
result.ErrNotImplemented(message)501 Not Implemented
result.ErrCredentialsInvalid(message)401 Unauthorized,并带 credentials-invalid 业务码
result.ErrPrincipalInvalid(message)401 Unauthorized,并带 principal-invalid 业务码

业务码范围

常见结果码范围如下:

范围含义
0成功
1000-1099认证与 challenge 错误
1100-1199授权错误
1200-1499资源、媒体类型和请求错误
1500-1699未实现与 SQL 相关错误
1900-1999未知错误
2000+业务错误

Fiber 错误映射

应用层会把部分 fiber.Error 映射为结构化 result 响应。

当前内置映射如下:

Fiber HTTP 状态Result 业务码Message key
401ErrCodeUnauthenticatedErrMessageUnauthenticated
403ErrCodeAccessDeniedErrMessageAccessDenied
404ErrCodeNotFoundErrMessageNotFound
415ErrCodeUnsupportedMediaTypeErrMessageUnsupportedMediaType
408ErrCodeRequestTimeoutErrMessageRequestTimeout

如果某个 fiber.Error 状态码没有映射,VEF 会先记录日志,再回退为通用 unknown error。

错误解析顺序

运行时,VEF 会按以下顺序处理错误:

  1. fiber.Error
  2. result.Error
  3. 其他未识别错误 -> result.ErrUnknown

这也是为什么对预期业务失败,应该优先返回显式的 result.Error,而不是不透明的普通错误。

常见模式

成功 + 数据

return result.Ok(user).Response(ctx)

成功 + 自定义消息

return result.Ok(
user,
result.WithMessage("user synced"),
).Response(ctx)

带业务码的业务错误

return result.Err(
"user already exists",
result.WithCode(result.ErrCodeRecordAlreadyExists),
)

显式覆盖 HTTP 状态

return result.Err(
"forbidden",
result.WithCode(result.ErrCodeAccessDenied),
result.WithStatus(fiber.StatusForbidden),
)

实践建议

  • result 当作对外响应契约来看待
  • 只要内置错误已经能表达你的语义,就优先复用
  • 当客户端需要按不同失败类型做不同处理时,再定义明确的业务码
  • 对预期业务失败,优先返回结构化 result.Error,不要返回随意拼接的字符串错误
  • 除非你有意绕开框架契约,否则不要手工输出原始 JSON 响应

下一步

继续阅读 认证,看认证失败是如何进入这一套结果模型的。