package middleware import ( "fmt" "runtime/debug" "github.com/gofiber/fiber/v2" "go.uber.org/zap" "github.com/break/junhong_cmp_fiber/pkg/constants" "github.com/break/junhong_cmp_fiber/pkg/errors" ) // Recover 创建自定义 panic 恢复中间件 // panic 会被转换为 AppError 并传递给 ErrorHandler 统一处理 func Recover(logger *zap.Logger) fiber.Handler { return func(c *fiber.Ctx) error { defer func() { if r := recover(); r != nil { // 获取请求 ID requestID := "" if rid := c.Locals(constants.ContextKeyRequestID); rid != nil { requestID = rid.(string) } // 捕获堆栈跟踪 stack := debug.Stack() // 记录 panic 信息(包含完整堆栈) logger.Error("Panic 已恢复", zap.String("request_id", requestID), zap.String("method", c.Method()), zap.String("path", c.Path()), zap.Any("panic", r), zap.String("stack", string(stack)), ) // 将 panic 转换为 AppError // 注意:这里不直接返回响应,而是返回错误让 ErrorHandler 处理 // 但由于我们在 defer 中,需要通过 c.Next() 返回错误 panicErr := errors.Wrap( errors.CodeInternalError, fmt.Sprintf("服务发生异常: %v", r), fmt.Errorf("panic: %v", r), ) // 直接调用 ErrorHandler(通过返回错误) // Fiber 会将这个错误传递给 ErrorHandler _ = c.App().Config().ErrorHandler(c, panicErr) } }() return c.Next() } }