创建仓库
This commit is contained in:
161
Go项目实战/03_基础设施/01_错误处理/03_README_错误处理.md
Normal file
161
Go项目实战/03_基础设施/01_错误处理/03_README_错误处理.md
Normal file
@@ -0,0 +1,161 @@
|
||||
---
|
||||
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/...
|
||||
```
|
||||
Reference in New Issue
Block a user