Go微服务错误需显式分类处理:BusinessError含Code/Message/HTTPStatus,SystemError含TraceID/cause/操作建议;统一映射gRPC与HTTP错误;包装错误用%w但生产环境须脱敏;所有错误传播必须响应context超时与cancel。
Go 语言没有异常机制,error 是一等公民,微服务中错误必须显式传递、分类、携带上下文,否则链路追踪失效、重试逻辑混乱、日志无法定位根因。
用自定义 error 类型区分业务错误与系统错误
直接返回 errors.New 或 fmt.Errorf 会导致下游无法判断错误性质——是该重试(如网络超时)、跳过(如用户参数非法),还是告警(如数据库连接中断)。应定义两个基础类型:
-
BusinessError:含Code(如"USER_NOT_FOUND")、HTTPStatus、可透传给前端的Message -
SystemError:含TraceID、原始错误(cause)、建议操作("retry_after_1s")
示例:
type BusinessError struct {
Code string
Message string
HTTPStatus int
}
func (e *BusinessError) Error() string { return e.Message }
调用方用 errors.As 判断类型,而非字符串匹配。
在 gRPC 和 HTTP 层统一错误映射
同一错误在不同协议层需转为对应语义:gRPC 要设 status.Code 和 status.Message,HTTP 要写入响应体和状态码。别在每个 handler 里重复写 switch。
- 定义全局映射表:
map[error]struct{ code codes.Code; httpStatus int } - 中间件/拦截器中统一处理:
grpc.UnaryServerInterceptor捕获返回的error,查表转成status.Error - HTTP handler 中用
http.Error或自定义响应结构,避免裸写w.WriteHeader(500)
漏掉映射会导致 gRPC 客户端收到 Unknown 状态码,HTTP 前端看到 500 却不知是参数错还是服务崩了。