# Implementation Plan: Fiber 错误处理集成 **Branch**: `003-error-handling` | **Date**: 2025-11-14 | **Spec**: [spec.md](./spec.md) **Input**: Feature specification from `/specs/003-error-handling/spec.md` ## Summary 实现统一的 Fiber 错误处理机制,包括全局 ErrorHandler、Panic 恢复、错误分类和安全的错误响应。核心目标是捕获所有错误和 panic,返回统一格式的 JSON 响应,同时隐藏敏感信息,记录完整的错误上下文到日志。 **技术方案**: 使用 Fiber ErrorHandler + defer/recover 双层保护,基于错误码范围映射 HTTP 状态码,Request ID 通过 Header 传递,日志采用静默失败策略。 ## Technical Context **Language/Version**: Go 1.25.4 **Primary Dependencies**: Fiber v2 (HTTP 框架), Zap (日志), sonic (JSON), 标准库 errors **Storage**: N/A (无持久化数据,仅运行时错误处理) **Testing**: Go 标准 testing 框架 + httptest **Target Platform**: Linux server (Docker 容器) **Project Type**: single (后端 API 服务) **Performance Goals**: 错误处理延迟 < 1ms (P95), 不显著增加请求处理时间 **Constraints**: - 错误响应不能暴露敏感信息 (数据库错误、文件路径、堆栈跟踪) - 日志失败不能阻塞响应 - ErrorHandler 自身必须防止 panic 无限循环 - 响应已发送后不能修改响应内容 **Scale/Scope**: - 影响所有 API 端点 (用户、订单、任务等) - 约 10+ 错误码定义 - 3-5 个新增/修改的文件 ## Constitution Check *GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.* **Tech Stack Adherence**: - [x] Feature uses Fiber + GORM + Viper + Zap + Lumberjack.v2 + Validator + sonic JSON + Asynq + PostgreSQL - [x] No native calls bypass framework (no `database/sql`, `net/http`, `encoding/json` direct use) - [x] All HTTP operations use Fiber framework - [x] All database operations use GORM (N/A - 本功能无数据库操作) - [x] All async tasks use Asynq (N/A - 本功能无异步任务) - [x] Uses Go official toolchain: `go fmt`, `go vet`, `golangci-lint` - [x] Uses Go Modules for dependency management **Code Quality Standards**: - [x] Follows Handler → Service → Store → Model architecture (本功能主要在 pkg/ 包中) - [x] Handler layer only handles HTTP, no business logic - [x] Service layer contains business logic with cross-module support (N/A - 本功能为基础设施) - [x] Store layer manages all data access with transaction support (N/A - 无数据访问) - [x] Uses dependency injection via struct fields (not constructor patterns) - [x] Unified error codes in `pkg/errors/` ✅ 本功能核心 - [x] Unified API responses via `pkg/response/` ✅ 本功能核心 - [x] All constants defined in `pkg/constants/` - [x] All Redis keys managed via key generation functions (N/A - 无 Redis 操作) - [x] **No hardcoded magic numbers or strings (3+ occurrences must be constants)** ✅ 错误码和消息均为常量 - [x] **Defined constants are used instead of hardcoding duplicate values** ✅ 错误消息通过映射表管理 - [x] **Code comments prefer Chinese for readability** ✅ 所有注释使用中文 - [x] **Log messages use Chinese** ✅ 所有日志消息使用中文 - [x] **Error messages support Chinese** ✅ 错误消息中文优先 - [x] All exported functions/types have Go-style doc comments - [x] Code formatted with `gofmt` - [x] Follows Effective Go and Go Code Review Comments **Documentation Standards** (Constitution Principle VII): - [x] Feature summary docs placed in `docs/{feature-id}/` mirroring `specs/{feature-id}/` - [x] Summary doc filenames use Chinese (功能总结.md, 使用指南.md, etc.) - [x] Summary doc content uses Chinese - [x] README.md updated with brief Chinese summary (2-3 sentences) - [x] Documentation is concise for first-time contributors **Go Idiomatic Design**: - [x] Package structure is flat (max 2-3 levels), organized by feature ✅ pkg/errors/ - [x] Interfaces are small (1-3 methods), defined at use site ✅ fiber.ErrorHandler - [x] No Java-style patterns: no I-prefix, no Impl-suffix, no getters/setters - [x] Error handling is explicit (return errors, no panic/recover abuse) ✅ 核心功能 - [x] Uses composition over inheritance - [x] Uses goroutines and channels (not thread pools) (N/A - 本功能无并发) - [x] Uses `context.Context` for cancellation and timeouts (N/A - 错误处理无需 context) - [x] Naming follows Go conventions: short receivers, consistent abbreviations - [x] No Hungarian notation or type prefixes - [x] Simple constructors (New/NewXxx), no Builder pattern unless necessary **Testing Standards**: - [x] Unit tests for all core business logic (Service layer) - [x] Integration tests for all API endpoints ✅ 错误处理集成测试 - [x] Tests use Go standard testing framework - [x] Test files named `*_test.go` in same directory - [x] Test functions use `Test` prefix, benchmarks use `Benchmark` prefix - [x] Table-driven tests for multiple test cases ✅ 多种错误场景测试 - [x] Test helpers marked with `t.Helper()` - [x] Tests are independent (no external service dependencies) - [x] Target coverage: 70%+ overall, 90%+ for core business ✅ 错误处理核心逻辑 90%+ **User Experience Consistency**: - [x] All APIs use unified JSON response format ✅ 本功能核心 - [x] Error responses include clear error codes and bilingual messages ✅ 中文消息 - [x] RESTful design principles followed - [x] Unified pagination parameters (N/A - 本功能无分页) - [x] Time fields use ISO 8601 format (RFC3339) ✅ timestamp 字段 - [x] Currency amounts use integers (N/A - 本功能无货币) **Performance Requirements**: - [x] API response time (P95) < 200ms, (P99) < 500ms ✅ 错误处理 < 1ms - [x] Batch operations use bulk queries/inserts (N/A - 本功能无批量操作) - [x] All database queries have appropriate indexes (N/A - 无数据库操作) - [x] List queries implement pagination (N/A - 无列表查询) - [x] Non-realtime operations use async tasks (N/A - 错误处理必须同步) - [x] Database and Redis connection pools properly configured (N/A) - [x] Uses goroutines/channels for concurrency (N/A - 错误处理同步执行) - [x] Uses `context.Context` for timeout control (N/A) - [x] Uses `sync.Pool` for frequently allocated objects (可选优化 - ErrorContext) **Access Logging Standards** (Constitution Principle VIII): - [x] ALL HTTP requests logged to access.log without exception ✅ 已有实现 - [x] Request parameters (query + body) logged (limited to 50KB) ✅ 已有实现 - [x] Response parameters (body) logged (limited to 50KB) ✅ 已有实现 - [x] Logging happens via centralized Logger middleware ✅ 已有实现 - [x] No middleware bypasses access logging ✅ ErrorHandler 不绕过日志 - [x] Body truncation indicates "... (truncated)" when over 50KB limit ✅ 已有实现 - [x] Access log includes all required fields ✅ 已有实现 ## Project Structure ### Documentation (this feature) **设计文档(specs/ 目录)**:开发前的规划和设计 ```text specs/003-error-handling/ ├── plan.md # This file (/speckit.plan command output) ├── research.md # Phase 0 output - 技术研究和决策 ├── data-model.md # Phase 1 output - 错误处理数据结构 ├── quickstart.md # Phase 1 output - 快速上手指南 ├── contracts/ # Phase 1 output - API contracts │ └── error-responses.yaml # 错误响应规范 (OpenAPI) └── tasks.md # Phase 2 output - 任务分解 (NOT created by /speckit.plan) ``` **总结文档(docs/ 目录)**:开发完成后的总结和使用指南(遵循 Constitution Principle VII) ```text docs/003-error-handling/ ├── 功能总结.md # 功能概述、核心实现、技术要点 ├── 使用指南.md # 如何使用错误处理机制 └── 架构说明.md # 错误处理架构设计(可选) ``` **README.md 更新**:完成功能后添加简短描述 ```markdown ## 核心功能 - **统一错误处理**:全局 ErrorHandler + Panic 恢复,统一错误响应格式,安全的敏感信息隐藏 ``` ### Source Code (repository root) ```text pkg/ ├── errors/ │ ├── errors.go # 已存在 - 需扩展 AppError │ ├── codes.go # 新增 - 错误码枚举和消息映射 │ ├── handler.go # 新增 - Fiber ErrorHandler 实现 │ └── context.go # 新增 - 错误上下文提取 ├── response/ │ └── response.go # 已存在 - 无需修改 ├── constants/ │ └── constants.go # 已存在 - 可能需要添加 Request ID 常量 └── logger/ └── logger.go # 已存在 - 无需修改 internal/middleware/ └── recover.go # 已存在 - 可能需要小幅调整 cmd/api/ └── main.go # 需修改 - 配置 Fiber ErrorHandler tests/integration/ └── error_handler_test.go # 新增 - 错误处理集成测试 ``` **Structure Decision**: 单一项目结构,错误处理作为基础设施包放在 `pkg/errors/` 下,供所有模块使用。与现有 `pkg/response/` 和 `pkg/logger/` 包协同工作。 ## Complexity Tracking > **Fill ONLY if Constitution Check has violations that must be justified** 无违反项。所有设计决策符合项目宪章要求。 ## Phase 0: Research (Complete ✅) **Output**: `research.md` 已完成技术研究,解决了以下关键问题: 1. Fiber ErrorHandler 机制和中间件集成 2. ErrorHandler 自身保护 (defer/recover) 3. 敏感信息识别和隐藏策略 4. 响应已发送后的错误处理 5. 日志系统集成和静默失败策略 6. 错误分类和 HTTP 状态码映射 7. Request ID 传递方式 **核心决策**: - 使用 Fiber ErrorHandler + defer/recover 双层保护 - 所有 5xx 错误返回通用消息,原始错误仅记录日志 - 日志采用静默失败策略,不阻塞响应 - 基于错误码范围 (1000-1999, 2000-2999) 映射 HTTP 状态码 - Request ID 仅在 Header 中传递,不在响应体中 ## Phase 1: Design & Contracts (Complete ✅) **Prerequisites:** `research.md` complete ✅ ### Data Model **Output**: `data-model.md` 定义了错误处理的核心数据结构: 1. **AppError**: 应用错误类型,包含错误码、消息、HTTP 状态码、错误链 2. **ErrorResponse**: 统一的 JSON 错误响应格式 3. **ErrorContext**: 错误发生时的请求上下文 (用于日志) 4. **ErrorCode**: 错误码枚举和消息映射 **关键实体**: - 无持久化实体 (运行时对象) - 错误处理流程数据流已定义 - 性能约束: ErrorContext 创建 < 0.1ms, 总延迟 < 1ms ### API Contracts **Output**: `contracts/error-responses.yaml` OpenAPI 3.0 格式定义了: - 统一的 ErrorResponse schema - 常见错误响应 (400, 401, 403, 404, 409, 429, 500, 503, 504) - 完整的错误码清单 (1001-1009, 2001-2006) - HTTP 状态码映射规则 - 安全规范和错误处理流程 - 实际示例 (成功、客户端错误、服务端错误、限流) ### Quick Start Guide **Output**: `quickstart.md` 为开发者提供: - 5 分钟快速开始指南 - 常用错误码表格 - Handler 中返回错误的 3 种方式 - 客户端错误处理示例 (TypeScript, Python) - 进阶使用: 自定义消息、错误链、Panic 恢复 - 调试技巧: Request ID 追踪 - 常见错误场景和最佳实践 - 测试示例和 FAQ ### Agent Context Update **Output**: CLAUDE.md updated ✅ 已更新 Claude 上下文文件,添加错误处理相关技术栈信息。 ## Phase 2: Implementation Planning **This phase is handled by `/speckit.tasks` command, NOT by `/speckit.plan`.** `/speckit.plan` 命令在此停止。下一步: 1. 运行 `/speckit.tasks` 生成详细的任务分解 (`tasks.md`) 2. 运行 `/speckit.implement` 执行实施 预期的 `tasks.md` 将包含: - **Task 1**: 扩展 pkg/errors/errors.go (添加 HTTPStatus 字段和方法) - **Task 2**: 创建 pkg/errors/codes.go (错误码枚举和消息映射) - **Task 3**: 创建 pkg/errors/handler.go (Fiber ErrorHandler 实现) - **Task 4**: 创建 pkg/errors/context.go (错误上下文提取) - **Task 5**: 更新 cmd/api/main.go (配置 ErrorHandler) - **Task 6**: 调整 internal/middleware/recover.go (如需) - **Task 7**: 创建集成测试 tests/integration/error_handler_test.go - **Task 8**: 更新文档 docs/003-error-handling/ ## Implementation Notes ### 关键依赖关系 1. **错误码定义优先**: `pkg/errors/codes.go` 必须先完成,因为其他组件依赖错误码常量 2. **AppError 扩展**: 扩展现有 `pkg/errors/errors.go`,保持向后兼容 3. **ErrorHandler 集成**: 在 `cmd/api/main.go` 中配置 Fiber ErrorHandler 4. **测试驱动**: 先编写集成测试,验证各种错误场景 ### 风险和缓解 **风险 1: ErrorHandler 自身 panic 导致服务崩溃** - 缓解: 使用 defer/recover 保护 ErrorHandler,失败时返回空响应 - **保护机制触发条件明确**: - **触发范围**: defer/recover 仅保护 ErrorHandler 函数本身的执行过程 - **捕获的异常**: 任何在 ErrorHandler 内部发生的 panic (包括日志系统崩溃、JSON 序列化失败、响应写入错误等) - **不捕获的异常**: Fiber 中间件链中的 panic 由 Recover 中间件处理,不在此保护范围内 - **失败响应**: 当 ErrorHandler 自身 panic 时,返回 HTTP 500 状态码,空响应体 (Content-Length: 0) - **日志记录**: 保护机制触发时的 panic 信息会被记录 (如果日志系统可用),但不阻塞响应返回 - **示例场景**: 1. Zap 日志系统崩溃 → defer/recover 捕获 → 返回 HTTP 500 空响应 2. sonic JSON 序列化失败 → defer/recover 捕获 → 返回 HTTP 500 空响应 3. c.Status().JSON() 写入响应失败 → defer/recover 捕获 → 返回 HTTP 500 空响应 4. 业务逻辑中的 panic → Recover 中间件捕获 → 传递给 ErrorHandler → ErrorHandler 正常处理 **风险 2: 日志系统失败阻塞响应** - 缓解: 日志调用使用 defer/recover,静默失败 **风险 3: 响应已发送后修改响应导致损坏** - 缓解: 检查响应状态,已发送则仅记录日志 **风险 4: 敏感信息泄露** - 缓解: 所有 5xx 错误返回通用消息,原始错误仅记录日志 ### 性能优化 1. **预分配错误对象**: 常见错误 (ErrMissingToken 等) 使用预定义对象 2. **避免字符串拼接**: 使用 `fmt.Errorf` 和 `%w` 包装错误 3. **异步日志**: Zap 已支持,无需额外配置 4. **ErrorContext 池化** (可选): 如果性能测试显示分配开销大,使用 `sync.Pool` ### 测试策略 **单元测试**: - pkg/errors/codes.go: 错误码映射函数 - pkg/errors/context.go: ErrorContext 提取逻辑 - pkg/errors/handler.go: ErrorHandler 核心逻辑 **集成测试**: - 参数验证失败 → 400 错误 - 认证失败 → 401 错误 - 资源未找到 → 404 错误 - 数据库错误 → 500 错误 (敏感信息已隐藏) - Panic 恢复 → 500 错误 (堆栈记录到日志) - 限流触发 → 429 错误 - 响应已发送后的错误处理 **性能测试**: - 错误处理延迟基准测试 - 并发场景下的错误处理 ### 部署注意事项 1. **向后兼容**: 现有错误处理代码继续工作,逐步迁移到新机制 2. **日志轮转**: 确保日志文件配置正确的轮转策略 3. **监控**: 配置告警规则监控 5xx 错误率 4. **文档**: 更新 API 文档,说明新的错误响应格式 ## Constitution Re-Check (Post-Design) ✅ 所有设计决策符合项目宪章要求: - Tech Stack Adherence: 使用 Fiber, Zap, sonic - Code Quality: 清晰的分层,统一的错误码和响应 - Go Idiomatic Design: 简单的结构体,显式的错误处理,无 Java 风格模式 - Testing Standards: 单元测试 + 集成测试,table-driven tests - Performance: 错误处理延迟 < 1ms - Security: 敏感信息隐藏,日志访问控制 --- **Plan Completion**: ✅ Phase 0 研究和 Phase 1 设计已完成 **Branch**: `003-error-handling` **Next Step**: 运行 `/speckit.tasks` 生成任务分解,然后 `/speckit.implement` 执行实施 **Generated Artifacts**: - ✅ `research.md` - 技术研究和决策 - ✅ `data-model.md` - 错误处理数据结构 - ✅ `contracts/error-responses.yaml` - 错误响应规范 (OpenAPI) - ✅ `quickstart.md` - 快速上手指南 - ✅ CLAUDE.md - 已更新 agent 上下文