Files
Inbox/Go项目实战/03_基础设施/01_错误处理/03_README_错误处理.md
2025-12-11 07:24:36 +08:00

5.3 KiB
Raw Permalink Blame History

tags, aliases, date created, date modified
tags aliases date created date modified
🛡️ 基础设施模块:错误处理与响应系统 (Infra: Error Handling & Response)
星期三, 十二月 10日 2025, 12:10:32 中午 星期三, 十二月 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 添加文案。

// code.go
const UserBalanceInsufficient = 20005

// msg.go
msg = map[int]string{
    // ...
    UserBalanceInsufficient: "User Balance Insufficient",
}

3.2 在 Handler 中使用 (推荐写法)

使用依赖注入的 app.Factory 创建响应器,而非直接调用 app.New

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 启动时注册全局中间件。

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)。

# 运行所有测试
go test -v -race ./internal/pkg/...