推荐用结构体实现error接口来定义自定义错误码,如AppError含Code、HTTPStatus、Message和Err字段,配合常量枚举与统一响应封装,确保可识别、可扩展、安全可控。
在 Go 中实现自定义错误码,核心是让错误具备可识别的类型、可携带的上下文(如码值、消息、HTTP 状态等),并支持统一处理(比如日志记录、API 响应封装)。推荐用 结构体实现 error 接口 的方式,比纯常量更灵活
、可扩展;常量可作为辅助,用于定义清晰的错误码枚举。
定义一个结构体(如 AppError),内嵌错误信息字段,并实现 Error() 方法。这样既能满足 Go 的 error 接口契约,又能附加业务语义。
Code int)、HTTP 状态码(HTTPStatus int)、用户提示(Message string)、原始错误(Err error,用于链式错误追踪)Error() 方法返回用户不友好的底层错误描述(供日志/调试用),而非 Message,避免敏感信息外泄NewAppError(code, msg, httpStatus))和包装函数(如 Wrap(err, code, msg))提升可读性将所有业务错误码集中定义为具名常量,避免魔法数字散落各处。配合 iota 可自动递增,也支持显式赋值以预留扩展空间。
const ( UserNotFound = 1001; InvalidPassword = 1002; OrderAlreadyPaid = 2001 )
map[int]string)或方法(func (c ErrorCode) String() string)实现错误码转描述return &AppError{Code: UserNotFound, Message: "用户不存在"})在 HTTP handler 或中间件中,对返回的 error 进行类型断言,提取结构体中的 Code 和 HTTPStatus,生成标准 JSON 响应。
errors.As() 判断是否为 *AppError,避免直接类型断言导致 panicAppError 的 error(如 io.EOF、json.UnmarshalError)视为服务端内部错误,返回通用码(如 50000)和 500 状态Message 语言版本)、自动上报错误码统计结构体错误不是“越重越好”,关键在职责清晰和易用性。
Error() 方法里返回 Message —— 它面向开发者,不是终端用户if err == ErrNotFound 难以携带动态上下文(如用户 ID),结构体才能承载fmt.Errorf("xxx: %w", err) 包装时,确保 AppError 支持 Unwrap() 方法以便调试