跳到主要内容

统一错误响应

如何定义统一错误响应结构?​

type ErrorResponse struct {
Code string `json:"code"`
Message string `json:"message"`
RequestID string `json:"request_id"`
Details map[string]any `json:"details,omitempty"`
}
  • status: HTTP 语义; 客户端可先按 4xx/5xx 分类;
  • code: 稳定业务标识; 不直接使用 Go error 文本;
  • message: 面向调用方的安全描述; 不泄露 SQL、路径或堆栈;
  • request_id: 连接响应、日志与 Trace;
  • details: 字段校验等结构化信息; 不作为任意调试数据容器;

如何把领域结果映射为 HTTP 状态?​

领域结果HTTPcode
参数无效400INVALID_ARGUMENT
未认证401UNAUTHENTICATED
无权限403PERMISSION_DENIED
文章不存在404ARTICLE_NOT_FOUND
版本或唯一键冲突409CONFLICT
限流429RATE_LIMITED
未分类内部错误500INTERNAL

如何保留错误根因并安全返回?​

if errors.Is(err, article.ErrNotFound) {
writeError(c, 404, "ARTICLE_NOT_FOUND", "article not found")
return
}
logger.Error("get article failed", zap.Error(err))
writeError(c, 500, "INTERNAL", "internal server error")
  • 领域错误: Service 暴露可分类的 sentinel 或类型;
  • 基础设施错误: Repository 使用 %w 包装,保留根因;
  • 记录一次: 最接近 HTTP 边界且掌握 request_id 的层记录完整错误;
  • panic: recovery 兜底为 500; panic 不替代正常错误处理;