feat: 实现统一错误处理系统 (003-error-handling)
- 新增统一错误码定义和管理 (pkg/errors/codes.go) - 新增全局错误处理器和中间件 (pkg/errors/handler.go, internal/middleware/error_handler.go) - 新增错误上下文管理 (pkg/errors/context.go) - 增强 Panic 恢复中间件 (internal/middleware/recover.go) - 新增完整的单元测试和集成测试 - 新增功能文档 (docs/003-error-handling/) - 新增功能规范 (specs/003-error-handling/) - 更新 CLAUDE.md 和 README.md
This commit is contained in:
@@ -1,47 +1,113 @@
|
||||
package errors
|
||||
|
||||
// 应用错误码
|
||||
// 错误码定义
|
||||
const (
|
||||
CodeSuccess = 0 // 成功
|
||||
CodeInternalError = 1000 // 内部服务器错误
|
||||
CodeMissingToken = 1001 // 缺失认证令牌
|
||||
CodeInvalidToken = 1002 // 令牌无效或已过期
|
||||
CodeTooManyRequests = 1003 // 请求过于频繁(限流)
|
||||
CodeAuthServiceUnavailable = 1004 // 认证服务不可用(Redis 宕机)
|
||||
CodeNotFound = 1005 // 资源不存在
|
||||
CodeBadRequest = 1006 // 请求参数错误
|
||||
CodeUnauthorized = 1007 // 未授权
|
||||
CodeForbidden = 1008 // 禁止访问
|
||||
// 成功
|
||||
CodeSuccess = 0
|
||||
|
||||
// 客户端错误 (1000-1999) -> 4xx HTTP 状态码
|
||||
CodeInvalidParam = 1001 // 参数验证失败
|
||||
CodeMissingToken = 1002 // 缺失认证令牌
|
||||
CodeInvalidToken = 1003 // 无效或过期的令牌
|
||||
CodeUnauthorized = 1004 // 未授权
|
||||
CodeForbidden = 1005 // 禁止访问
|
||||
CodeNotFound = 1006 // 资源未找到
|
||||
CodeConflict = 1007 // 资源冲突
|
||||
CodeTooManyRequests = 1008 // 请求过多
|
||||
CodeRequestTooLarge = 1009 // 请求体过大
|
||||
|
||||
// 服务端错误 (2000-2999) -> 5xx HTTP 状态码
|
||||
CodeInternalError = 2001 // 内部服务器错误
|
||||
CodeDatabaseError = 2002 // 数据库错误
|
||||
CodeRedisError = 2003 // Redis 错误
|
||||
CodeServiceUnavailable = 2004 // 服务不可用
|
||||
CodeTimeout = 2005 // 请求超时
|
||||
CodeTaskQueueError = 2006 // 任务队列错误
|
||||
|
||||
// 向后兼容的别名(供现有代码使用)
|
||||
CodeBadRequest = CodeInvalidParam // 别名:参数验证失败
|
||||
CodeAuthServiceUnavailable = CodeServiceUnavailable // 别名:认证服务不可用
|
||||
)
|
||||
|
||||
// ErrorMessage 表示双语错误消息
|
||||
type ErrorMessage struct {
|
||||
EN string
|
||||
ZH string
|
||||
// errorMessages 错误消息映射表(中文)
|
||||
var errorMessages = map[int]string{
|
||||
CodeSuccess: "成功",
|
||||
CodeInvalidParam: "参数验证失败",
|
||||
CodeMissingToken: "缺失认证令牌",
|
||||
CodeInvalidToken: "无效或过期的令牌",
|
||||
CodeUnauthorized: "未授权访问",
|
||||
CodeForbidden: "禁止访问",
|
||||
CodeNotFound: "资源未找到",
|
||||
CodeConflict: "资源冲突",
|
||||
CodeTooManyRequests: "请求过多,请稍后重试",
|
||||
CodeRequestTooLarge: "请求体过大",
|
||||
CodeInternalError: "内部服务器错误",
|
||||
CodeDatabaseError: "数据库错误",
|
||||
CodeRedisError: "缓存服务错误",
|
||||
CodeServiceUnavailable: "服务暂时不可用",
|
||||
CodeTimeout: "请求超时",
|
||||
CodeTaskQueueError: "任务队列错误",
|
||||
}
|
||||
|
||||
// errorMessages 将错误码映射到双语消息
|
||||
var errorMessages = map[int]ErrorMessage{
|
||||
CodeSuccess: {"Success", "成功"},
|
||||
CodeInternalError: {"Internal server error", "内部服务器错误"},
|
||||
CodeMissingToken: {"Missing authentication token", "缺失认证令牌"},
|
||||
CodeInvalidToken: {"Invalid or expired token", "令牌无效或已过期"},
|
||||
CodeTooManyRequests: {"Too many requests", "请求过于频繁"},
|
||||
CodeAuthServiceUnavailable: {"Authentication service unavailable", "认证服务不可用"},
|
||||
CodeNotFound: {"Resource not found", "资源不存在"},
|
||||
CodeBadRequest: {"Bad request", "请求参数错误"},
|
||||
CodeUnauthorized: {"Unauthorized", "未授权"},
|
||||
CodeForbidden: {"Forbidden", "禁止访问"},
|
||||
}
|
||||
|
||||
// GetMessage 根据错误码和语言返回错误消息
|
||||
// GetMessage 获取错误码对应的消息
|
||||
// lang 参数暂时保留以便未来支持多语言,目前仅支持中文
|
||||
func GetMessage(code int, lang string) string {
|
||||
msg, ok := errorMessages[code]
|
||||
if !ok {
|
||||
return "Unknown error"
|
||||
if msg, ok := errorMessages[code]; ok {
|
||||
return msg
|
||||
}
|
||||
if lang == "zh" || lang == "zh-CN" {
|
||||
return msg.ZH
|
||||
// 未定义的错误码返回默认消息
|
||||
if code >= 2000 && code < 3000 {
|
||||
return "内部服务器错误"
|
||||
}
|
||||
return msg.EN
|
||||
return "请求处理失败"
|
||||
}
|
||||
|
||||
// GetHTTPStatus 将错误码映射为 HTTP 状态码
|
||||
func GetHTTPStatus(code int) int {
|
||||
switch code {
|
||||
case CodeSuccess:
|
||||
return 200 // OK
|
||||
case CodeInvalidParam, CodeRequestTooLarge:
|
||||
return 400 // Bad Request
|
||||
case CodeMissingToken, CodeInvalidToken, CodeUnauthorized:
|
||||
return 401 // Unauthorized
|
||||
case CodeForbidden:
|
||||
return 403 // Forbidden
|
||||
case CodeNotFound:
|
||||
return 404 // Not Found
|
||||
case CodeConflict:
|
||||
return 409 // Conflict
|
||||
case CodeTooManyRequests:
|
||||
return 429 // Too Many Requests
|
||||
case CodeServiceUnavailable:
|
||||
return 503 // Service Unavailable
|
||||
case CodeTimeout:
|
||||
return 504 // Gateway Timeout
|
||||
default:
|
||||
// 服务端错误(2000-2999)默认映射为 500
|
||||
if code >= 2000 && code < 3000 {
|
||||
return 500 // Internal Server Error
|
||||
}
|
||||
// 客户端错误(1000-1999)默认映射为 400
|
||||
if code >= 1000 && code < 2000 {
|
||||
return 400 // Bad Request
|
||||
}
|
||||
// 其他未知错误默认为 500
|
||||
return 500 // Internal Server Error
|
||||
}
|
||||
}
|
||||
|
||||
// GetLogLevel 将错误码映射为日志级别
|
||||
// 返回值: "warn" (客户端错误), "error" (服务端错误), "info" (成功)
|
||||
func GetLogLevel(code int) string {
|
||||
if code == 0 {
|
||||
return "info" // 成功
|
||||
}
|
||||
if code >= 2000 && code < 3000 {
|
||||
return "error" // 服务端错误
|
||||
}
|
||||
if code >= 1000 && code < 2000 {
|
||||
return "warn" // 客户端错误
|
||||
}
|
||||
return "error" // 默认为错误级别
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user