NestJS如何在onApplicationBootstrap及定时任务中全局处理错误?
非Controller场景的全局错误处理方案
Nest的全局异常过滤器、拦截器默认只作用于HTTP请求链路(也就是Controller处理请求的上下文),像onApplicationBootstrap启动钩子、@Cron定时任务这类脱离HTTP请求的场景,自然无法触发默认的全局异常处理逻辑。下面是几种可行的解决方式:
1. 自定义全局错误处理服务 + 手动捕获
这是最通用的方案,不管是启动钩子还是定时任务都适用:
步骤1:创建全局错误处理服务
import { Injectable, Logger } from '@nestjs/common'; import { HttpException } from '@nestjs/common'; @Injectable() export class ErrorHandlingService { private readonly logger = new Logger(ErrorHandlingService.name); handleError(exception: unknown) { // 可根据异常类型做差异化处理:日志记录、告警推送、数据回滚等 if (exception instanceof HttpException) { this.logger.error(`业务异常: ${exception.message}`, exception.stack); // 示例:调用告警接口 // await this.alertService.sendAlert(exception.getStatus(), exception.message); } else { this.logger.error(`未知异常`, exception.stack); } } }
步骤2:在调用处手动捕获异常并处理
在TasksService中注入错误处理服务,用try/catch包裹可能抛出异常的方法调用:
import { Injectable, OnApplicationBootstrap } from '@nestjs/common'; import { Cron, CronExpression } from '@nestjs/schedule'; import { TowerService } from './tower.service'; import { ErrorHandlingService } from './error-handling.service'; @Injectable() export class TasksService implements OnApplicationBootstrap { constructor( private readonly towerService: TowerService, private readonly errorHandlingService: ErrorHandlingService, ) {} async onApplicationBootstrap() { try { await this.towerService.sendTowerJob(); } catch (e) { this.errorHandlingService.handleError(e); } } @Cron(CronExpression.EVERY_HOUR) async scheduledTowerJob() { try { await this.towerService.sendTowerJob(); } catch (e) { this.errorHandlingService.handleError(e); } } }
2. 复用现有全局异常过滤器(适配非HTTP场景)
如果已经有现成的全局异常过滤器,不想重复写处理逻辑,可以手动调用过滤器的catch方法,但需要先调整过滤器逻辑,让它兼容无HTTP上下文的场景:
调整全局过滤器逻辑
import { ExceptionFilter, Catch, ArgumentsHost, HttpException } from '@nestjs/common'; @Catch(HttpException) export class GlobalHttpExceptionFilter implements ExceptionFilter { catch(exception: HttpException, host?: ArgumentsHost) { // 处理HTTP请求场景 if (host) { const ctx = host.switchToHttp(); const response = ctx.getResponse(); const status = exception.getStatus(); response.status(status).json({ statusCode: status, message: exception.message, }); } else { // 处理非HTTP场景(启动钩子、定时任务) console.error('非HTTP场景捕获异常:', exception.message, exception.stack); // 可复用错误处理逻辑,比如调用ErrorHandlingService } } }
在调用处手动调用过滤器
import { Injectable, OnApplicationBootstrap } from '@nestjs/common'; import { Cron, CronExpression } from '@nestjs/schedule'; import { TowerService } from './tower.service'; import { GlobalHttpExceptionFilter } from './global-http-exception.filter'; @Injectable() export class TasksService implements OnApplicationBootstrap { constructor( private readonly towerService: TowerService, private readonly globalFilter: GlobalHttpExceptionFilter, ) {} async onApplicationBootstrap() { try { await this.towerService.sendTowerJob(); } catch (e) { this.globalFilter.catch(e); // 不传host,触发非HTTP场景逻辑 } } }
3. 定时任务专属全局错误处理
Nest的定时任务模块提供了全局错误处理配置,直接在ScheduleModule初始化时配置即可,无需每个任务都写try/catch:
import { Module } from '@nestjs/common'; import { ScheduleModule } from '@nestjs/schedule'; import { TasksService } from './tasks.service'; import { ErrorHandlingService } from './error-handling.service'; @Module({ imports: [ ScheduleModule.forRoot({ errorHandler: (err) => { // 统一处理所有定时任务的异常 const errorHandler = new ErrorHandlingService(); errorHandler.handleError(err); // 若ErrorHandlingService为全局服务,可通过依赖注入获取(此处为简化示例) }, }), ], providers: [TasksService, ErrorHandlingService], }) export class TasksModule {}
内容的提问来源于stack exchange,提问作者Jc Yao
相关产品推荐
相关产品推荐

