diff --git a/backend/services/admin-service/src/api/interceptors/maintenance.interceptor.ts b/backend/services/admin-service/src/api/interceptors/maintenance.interceptor.ts index 342e87ee..260c089c 100644 --- a/backend/services/admin-service/src/api/interceptors/maintenance.interceptor.ts +++ b/backend/services/admin-service/src/api/interceptors/maintenance.interceptor.ts @@ -6,6 +6,7 @@ import { HttpException, HttpStatus, Inject, + Logger, } from '@nestjs/common'; import { Observable } from 'rxjs'; import { @@ -19,6 +20,8 @@ import { */ @Injectable() export class MaintenanceInterceptor implements NestInterceptor { + private readonly logger = new Logger(MaintenanceInterceptor.name); + constructor( @Inject(SYSTEM_MAINTENANCE_REPOSITORY) private readonly maintenanceRepo: ISystemMaintenanceRepository, @@ -28,46 +31,65 @@ export class MaintenanceInterceptor implements NestInterceptor { context: ExecutionContext, next: CallHandler, ): Promise> { - const request = context.switchToHttp().getRequest(); - const path = request.path; + try { + const request = context.switchToHttp().getRequest(); + // 获取请求路径,优先使用 url(去除查询参数) + const path = (request.url?.split('?')[0] || request.path) as string; - // 白名单路径 - 这些路径在维护期间也可以访问 - const whitelist = [ - '/mobile/system/maintenance-status', // 维护状态检查 - '/health', // 健康检查 - '/api/health', // 健康检查(带前缀) - ]; + // 白名单路径 - 这些路径在维护期间也可以访问 + // 支持带 /api/v1 前缀和不带前缀的两种情况 + const whitelist = [ + '/api/v1/mobile/system/maintenance-status', + '/mobile/system/maintenance-status', + '/api/v1/health', + '/health', + ]; - // 只拦截移动端 API(以 /mobile 开头的路径) - if (!path.startsWith('/mobile')) { - return next.handle(); - } + // 检查是否是移动端 API(需要同时检查带前缀和不带前缀的路径) + const isMobileApi = + path.includes('/mobile/') || + path.startsWith('/mobile'); - // 检查是否在白名单中 - if (whitelist.some((p) => path.startsWith(p))) { - return next.handle(); - } + // 非移动端 API,直接放行 + if (!isMobileApi) { + return next.handle(); + } - // 检查是否在维护中 - const activeMaintenance = await this.maintenanceRepo.findActiveMaintenance(); + // 检查是否在白名单中 + if (whitelist.some((p) => path === p || path.startsWith(p + '/'))) { + return next.handle(); + } - if (activeMaintenance) { - throw new HttpException( - { - statusCode: HttpStatus.SERVICE_UNAVAILABLE, - error: 'Service Unavailable', - message: '系统维护中', - maintenance: { - inMaintenance: true, - title: activeMaintenance.title, - message: activeMaintenance.message, - endTime: activeMaintenance.endTime, + // 检查是否在维护中 + const activeMaintenance = await this.maintenanceRepo.findActiveMaintenance(); + + if (activeMaintenance) { + this.logger.warn(`系统维护中,阻断请求: ${path}`); + throw new HttpException( + { + statusCode: HttpStatus.SERVICE_UNAVAILABLE, + error: 'Service Unavailable', + message: '系统维护中', + maintenance: { + inMaintenance: true, + title: activeMaintenance.title, + message: activeMaintenance.message, + endTime: activeMaintenance.endTime, + }, }, - }, - HttpStatus.SERVICE_UNAVAILABLE, - ); - } + HttpStatus.SERVICE_UNAVAILABLE, + ); + } - return next.handle(); + return next.handle(); + } catch (error) { + // 如果是我们抛出的 HttpException,直接重新抛出 + if (error instanceof HttpException) { + throw error; + } + // 其他错误(如数据库错误),记录日志但不阻断请求 + this.logger.error(`维护状态检查失败,放行请求: ${error.message}`); + return next.handle(); + } } }