--- tags: [] aliases: - "🛡️ 基础设施模块:错误处理与响应系统 (Infra: Error Handling & Response)" date created: 星期三, 十二月 10日 2025, 12:10:32 中午 date modified: 星期三, 十二月 10日 2025, 12:12:02 中午 --- # 🛡️ 基础设施模块:错误处理与响应系统 (Infra: Error Handling & Response) ## 1\. 模块概述 本模块实现了 **Modular Clean Architecture** 中的基础设施层 (`Level 0` & `Level 1`),提供了一套统一的、安全的、可观测的 HTTP 响应机制。 **核心能力:** - **统一契约:** 所有 API 响应(成功、失败、Panic、404)严格遵循 `{code, msg, data, trace_id}` 结构。 - **安全降级:** 自动识别业务错误与系统错误。对系统级错误(如 SQL 失败)进行“掩码”处理,防止敏感信息泄露。 - **可观测性:** 集成 Prometheus 埋点,通过 `X-Biz-Code` 实现业务级监控;全链路 TraceID 自动注入。 - **开发体验:** 提供 `Responder` 接口与工厂模式,支持 Handler 层的依赖注入与 Mock 测试。 ----- ## 2\. 文件清单 (File Manifest) 以下代码位于项目根目录 `gitea-aliyun/Klein/enterprise-cms-core/` 下: ### Level 0: 基础领域层 (`internal/pkg/ecode`) > **依赖:** 零依赖 (仅标准库) | 文件名 | 类型 | 核心职责 | | :--- | :--- | :--- | | `code.go` | Const | **错误码注册表**。定义 `1xxxx` (系统) 和 `2xxxx` (业务) 常量。 | | `msg.go` | Data | **文案映射**。维护全局 `map[int]string`,提供并发安全的 `GetMsg`。 | | `error.go` | Struct | **错误实体**。实现 `error` 接口,支持 `WithMsg`/`WithDetails` 扩展。 | | `ecode_test.go` | Test | 验证并发安全性及不可变性。 | ### Level 1: 应用工具层 (`internal/pkg/app`) > **依赖:** `gin`, `ecode` | 文件名 | 类型 | 核心职责 | | :--- | :--- | :--- | | `responder.go` | Interface | **接口定义**。定义 `Responder` 接口与 `Factory` 函数类型,用于解耦。 | | `response.go` | Impl | **核心实现**。封装 Gin Context,实现 JSON 序列化、错误清洗、监控埋点。 | | `options.go` | Pattern | **功能选项**。提供 `WithTraceID` 等扩展配置。 | | `response_test.go` | Test | 验证 JSON 契约、空指针防御及错误降级逻辑。 | ### Global: 全局中间件 (`internal/middleware`) > **依赖:** `gin`, `pkg/app`, `pkg/ecode`, `prometheus` | 文件名 | 类型 | 核心职责 | | :--- | :--- | :--- | | `recovery.go` | Safety | **Panic 兜底**。捕获 Panic 并转换为标准 JSON 500 响应。 | | `not_found.go` | Route | **404 兜底**。将无路由请求转换为标准 JSON 404 响应。 | | `metrics.go` | Monitor | **业务监控**。采集 `http_requests_total` 指标,包含 `biz_code` 标签。 | ----- ## 3\. 快速上手 (Quick Start) ### 3.1 定义新错误 在 `internal/pkg/ecode/code.go` 添加常量,并在 `msg.go` 添加文案。 ```go // code.go const UserBalanceInsufficient = 20005 // msg.go msg = map[int]string{ // ... UserBalanceInsufficient: "User Balance Insufficient", } ``` ### 3.2 在 Handler 中使用 (推荐写法) 使用依赖注入的 `app.Factory` 创建响应器,而非直接调用 `app.New`。 ```go import ( "github.com/gin-gonic/gin" "gitea-aliyun/Klein/enterprise-cms-core/internal/pkg/app" "gitea-aliyun/Klein/enterprise-cms-core/internal/pkg/ecode" ) type UserHandler struct { // 注入 Responder 工厂,便于测试 Mock RespFactory app.Factory } func (h *UserHandler) Create(c *gin.Context) { // 1. 创建响应器 resp := h.RespFactory(c) // 2. 模拟业务逻辑 if err := h.Service.Create(); err != nil { // 自动处理错误:如果是业务错误直接返回;如果是系统错误则降级并记录日志 resp.Error(err) return } // 3. 成功响应 resp.Success(gin.H{"status": "created"}) } ``` ### 3.3 系统接入 (Main.go) 在 HTTP Server 启动时注册全局中间件。 ```go r := gin.New() // 1. Recovery (必须最先注册) r.Use(middleware.Recovery()) // 2. Metrics (监控业务码) r.Use(middleware.BusinessMetrics()) // ... 注册业务路由 ... // 3. 404 处理 (最后注册) r.NoRoute(middleware.NotFound()) ``` ----- ## 4\. 设计决策说明 (Architecture Decisions) ### A. HTTP 200 Always 策略 - **规则:** 除非网络层崩溃,所有接口(包括业务错误和系统错误)均返回 `HTTP 200 OK`。 - **原因:** 防止网关(Nginx/ALB)拦截非 200 响应并替换 Body,确保前端始终能解析 JSON 中的 `code`。 ### B. 安全掩码 (Security Masking) - **输入:** `db.Query` 失败返回 `sql: connection refused`。 - **输出:** 前端收到 `{ "code": 10000, "msg": "Internal Server Error" }`。 - **日志:** 服务端 Error Log 记录原始堆栈。 - **目的:** 杜绝数据库结构、IP 等敏感信息通过报错接口泄露。 ### C. 监控指标 (Metrics) - **指标名:** `http_requests_total` - **关键标签:** `biz_code` (业务状态码)。 - **SRE 告警:** 请针对 `biz_code >= 10000` (系统错误) 配置告警,而非 HTTP Status Code。 ----- ## 5\. 测试指南 本模块已包含完整的单元测试与竞态检测 (Race Detection)。 ```bash # 运行所有测试 go test -v -race ./internal/pkg/... ```