Files
junhong_cmp_fiber/pkg/errors/context.go
huang fb83c9a706 feat: 实现统一错误处理系统 (003-error-handling)
- 新增统一错误码定义和管理 (pkg/errors/codes.go)
- 新增全局错误处理器和中间件 (pkg/errors/handler.go, internal/middleware/error_handler.go)
- 新增错误上下文管理 (pkg/errors/context.go)
- 增强 Panic 恢复中间件 (internal/middleware/recover.go)
- 新增完整的单元测试和集成测试
- 新增功能文档 (docs/003-error-handling/)
- 新增功能规范 (specs/003-error-handling/)
- 更新 CLAUDE.md 和 README.md
2025-11-15 12:17:44 +08:00

91 lines
2.2 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package errors
import (
"github.com/gofiber/fiber/v2"
"go.uber.org/zap"
"github.com/break/junhong_cmp_fiber/pkg/constants"
)
// ErrorContext 错误发生时的请求上下文(用于日志记录)
type ErrorContext struct {
RequestID string // 请求 ID唯一标识
Method string // HTTP 方法
Path string // 请求路径
Query string // Query 参数
Body string // 请求 Body限制 50KB
IP string // 客户端 IP
UserAgent string // User-Agent
UserID string // 用户 ID如果已认证
}
const (
// MaxBodyLogSize 请求 Body 日志记录最大字节数50KB
MaxBodyLogSize = 50 * 1024
)
// FromFiberContext 从 Fiber Context 提取错误上下文
func FromFiberContext(c *fiber.Ctx) *ErrorContext {
ctx := &ErrorContext{
Method: c.Method(),
Path: c.Path(),
Query: c.Request().URI().QueryArgs().String(),
IP: c.IP(),
UserAgent: c.Get("User-Agent"),
}
// 提取 Request ID
if rid := c.Locals(constants.ContextKeyRequestID); rid != nil {
ctx.RequestID = rid.(string)
}
if ctx.RequestID == "" {
ctx.RequestID = c.Get("X-Request-ID")
}
// 提取 User ID如果已认证
if uid := c.Locals("user_id"); uid != nil {
if userID, ok := uid.(string); ok {
ctx.UserID = userID
}
}
// 提取请求 Body限制 50KB
bodyBytes := c.Body()
if len(bodyBytes) > 0 {
if len(bodyBytes) > MaxBodyLogSize {
// 超过限制时截断并添加提示
ctx.Body = string(bodyBytes[:MaxBodyLogSize]) + " ... (truncated)"
} else {
ctx.Body = string(bodyBytes)
}
}
return ctx
}
// ToLogFields 转换为 Zap 日志字段
func (ec *ErrorContext) ToLogFields() []zap.Field {
fields := []zap.Field{
zap.String("request_id", ec.RequestID),
zap.String("method", ec.Method),
zap.String("path", ec.Path),
zap.String("ip", ec.IP),
}
// 可选字段(非空时添加)
if ec.Query != "" {
fields = append(fields, zap.String("query", ec.Query))
}
if ec.Body != "" {
fields = append(fields, zap.String("body", ec.Body))
}
if ec.UserAgent != "" {
fields = append(fields, zap.String("user_agent", ec.UserAgent))
}
if ec.UserID != "" {
fields = append(fields, zap.String("user_id", ec.UserID))
}
return fields
}