fix(admin-service): 修复维护拦截器路径检测和错误处理
问题:添加系统维护检测后站内通知功能失效 修复: 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 <noreply@anthropic.com>
This commit is contained in:
parent
c392142562
commit
fea0b42223
|
|
@ -6,6 +6,7 @@ import {
|
||||||
HttpException,
|
HttpException,
|
||||||
HttpStatus,
|
HttpStatus,
|
||||||
Inject,
|
Inject,
|
||||||
|
Logger,
|
||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
import {
|
import {
|
||||||
|
|
@ -19,6 +20,8 @@ import {
|
||||||
*/
|
*/
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class MaintenanceInterceptor implements NestInterceptor {
|
export class MaintenanceInterceptor implements NestInterceptor {
|
||||||
|
private readonly logger = new Logger(MaintenanceInterceptor.name);
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@Inject(SYSTEM_MAINTENANCE_REPOSITORY)
|
@Inject(SYSTEM_MAINTENANCE_REPOSITORY)
|
||||||
private readonly maintenanceRepo: ISystemMaintenanceRepository,
|
private readonly maintenanceRepo: ISystemMaintenanceRepository,
|
||||||
|
|
@ -28,46 +31,65 @@ export class MaintenanceInterceptor implements NestInterceptor {
|
||||||
context: ExecutionContext,
|
context: ExecutionContext,
|
||||||
next: CallHandler,
|
next: CallHandler,
|
||||||
): Promise<Observable<any>> {
|
): Promise<Observable<any>> {
|
||||||
const request = context.switchToHttp().getRequest();
|
try {
|
||||||
const path = request.path;
|
const request = context.switchToHttp().getRequest();
|
||||||
|
// 获取请求路径,优先使用 url(去除查询参数)
|
||||||
|
const path = (request.url?.split('?')[0] || request.path) as string;
|
||||||
|
|
||||||
// 白名单路径 - 这些路径在维护期间也可以访问
|
// 白名单路径 - 这些路径在维护期间也可以访问
|
||||||
const whitelist = [
|
// 支持带 /api/v1 前缀和不带前缀的两种情况
|
||||||
'/mobile/system/maintenance-status', // 维护状态检查
|
const whitelist = [
|
||||||
'/health', // 健康检查
|
'/api/v1/mobile/system/maintenance-status',
|
||||||
'/api/health', // 健康检查(带前缀)
|
'/mobile/system/maintenance-status',
|
||||||
];
|
'/api/v1/health',
|
||||||
|
'/health',
|
||||||
|
];
|
||||||
|
|
||||||
// 只拦截移动端 API(以 /mobile 开头的路径)
|
// 检查是否是移动端 API(需要同时检查带前缀和不带前缀的路径)
|
||||||
if (!path.startsWith('/mobile')) {
|
const isMobileApi =
|
||||||
return next.handle();
|
path.includes('/mobile/') ||
|
||||||
}
|
path.startsWith('/mobile');
|
||||||
|
|
||||||
// 检查是否在白名单中
|
// 非移动端 API,直接放行
|
||||||
if (whitelist.some((p) => path.startsWith(p))) {
|
if (!isMobileApi) {
|
||||||
return next.handle();
|
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(
|
const activeMaintenance = await this.maintenanceRepo.findActiveMaintenance();
|
||||||
{
|
|
||||||
statusCode: HttpStatus.SERVICE_UNAVAILABLE,
|
if (activeMaintenance) {
|
||||||
error: 'Service Unavailable',
|
this.logger.warn(`系统维护中,阻断请求: ${path}`);
|
||||||
message: '系统维护中',
|
throw new HttpException(
|
||||||
maintenance: {
|
{
|
||||||
inMaintenance: true,
|
statusCode: HttpStatus.SERVICE_UNAVAILABLE,
|
||||||
title: activeMaintenance.title,
|
error: 'Service Unavailable',
|
||||||
message: activeMaintenance.message,
|
message: '系统维护中',
|
||||||
endTime: activeMaintenance.endTime,
|
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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue