From fea0b422231897ad022dda99fccd314ddd63b963 Mon Sep 17 00:00:00 2001 From: hailin Date: Fri, 2 Jan 2026 05:01:32 -0800 Subject: [PATCH] =?UTF-8?q?fix(admin-service):=20=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E7=BB=B4=E6=8A=A4=E6=8B=A6=E6=88=AA=E5=99=A8=E8=B7=AF=E5=BE=84?= =?UTF-8?q?=E6=A3=80=E6=B5=8B=E5=92=8C=E9=94=99=E8=AF=AF=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 问题:添加系统维护检测后站内通知功能失效 修复: 1. 使用 request.url 获取完整路径(包含 /api/v1 前缀) 2. 同时支持带前缀和不带前缀的路径检测 3. 添加 try-catch 错误处理,数据库错误时放行请求而非阻断 4. 添加日志记录便于调试 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- .../interceptors/maintenance.interceptor.ts | 90 ++++++++++++------- 1 file changed, 56 insertions(+), 34 deletions(-) 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(); + } } }