/** * 维护模式中间件 * * 功能描述: * - 检查系统是否处于维护模式 * - 在维护期间阻止用户访问API * - 提供维护状态和预计恢复时间信息 * * 使用场景: * - 系统升级维护 * - 数据库迁移 * - 紧急故障修复 * - 定期维护窗口 * * @author kiro-ai * @version 1.0.0 * @since 2025-12-24 */ import { Injectable, NestMiddleware } from '@nestjs/common'; import { Request, Response, NextFunction } from 'express'; import { ConfigService } from '@nestjs/config'; import { Logger } from '@nestjs/common'; /** * 维护模式响应接口 */ interface MaintenanceResponse { /** 请求是否成功 */ success: boolean; /** 响应消息 */ message: string; /** 错误代码 */ error_code: string; /** 维护信息 */ maintenance_info?: { /** 维护开始时间 */ start_time: string; /** 预计结束时间 */ estimated_end_time?: string; /** 重试间隔(秒) */ retry_after: number; /** 维护原因 */ reason?: string; }; } @Injectable() export class MaintenanceMiddleware implements NestMiddleware { private readonly logger = new Logger(MaintenanceMiddleware.name); constructor(private readonly configService: ConfigService) {} /** * 中间件处理函数 * * 业务逻辑: * 1. 检查维护模式环境变量 * 2. 如果处于维护模式,返回503状态码 * 3. 提供维护信息和重试建议 * 4. 记录维护期间的访问尝试 * * @param req HTTP请求对象 * @param res HTTP响应对象 * @param next 下一个中间件函数 */ use(req: Request, res: Response, next: NextFunction) { // 1. 检查维护模式状态 const isMaintenanceMode = this.configService.get('MAINTENANCE_MODE') === 'true'; if (!isMaintenanceMode) { // 非维护模式,继续处理请求 next(); return; } // 2. 记录维护期间的访问尝试 this.logger.warn('维护模式:拒绝访问请求', { operation: 'maintenance_check', method: req.method, url: req.url, userAgent: req.get('User-Agent'), ip: req.ip, timestamp: new Date().toISOString() }); // 3. 获取维护配置信息 const maintenanceStartTime = this.configService.get('MAINTENANCE_START_TIME') || new Date().toISOString(); const maintenanceEndTime = this.configService.get('MAINTENANCE_END_TIME'); const maintenanceReason = this.configService.get('MAINTENANCE_REASON') || '系统维护升级'; const retryAfter = this.configService.get('MAINTENANCE_RETRY_AFTER') || 1800; // 默认30分钟 // 4. 构建维护模式响应 const maintenanceResponse: MaintenanceResponse = { success: false, message: '系统正在维护中,请稍后再试', error_code: 'SERVICE_UNAVAILABLE', maintenance_info: { start_time: maintenanceStartTime, estimated_end_time: maintenanceEndTime, retry_after: retryAfter, reason: maintenanceReason } }; // 5. 设置HTTP响应头 res.setHeader('Retry-After', retryAfter.toString()); res.setHeader('Content-Type', 'application/json'); // 6. 返回503服务不可用状态 res.status(503).json(maintenanceResponse); } /** * 检查维护模式是否启用 * * @returns 是否处于维护模式 */ isMaintenanceEnabled(): boolean { return this.configService.get('MAINTENANCE_MODE') === 'true'; } /** * 获取维护信息 * * @returns 维护配置信息 */ getMaintenanceInfo() { return { enabled: this.isMaintenanceEnabled(), startTime: this.configService.get('MAINTENANCE_START_TIME'), endTime: this.configService.get('MAINTENANCE_END_TIME'), reason: this.configService.get('MAINTENANCE_REASON'), retryAfter: this.configService.get('MAINTENANCE_RETRY_AFTER') }; } }