NestJS中AllExceptionFilter触发异常后服务无法接收请求如何解决?
NestJS全局异常过滤器导致服务无法接收请求的问题解决
问题描述
使用NestJS并创建了AllExceptionFilter全局异常过滤器后,通过httpService发起POST请求返回错误时,NestJS便无法再接收RESTful API请求。
错误日志
/Users/username/Documents/workspace/project/nestjs/src/shared/filters/custom-exception.filter.ts:29 path: httpAdapter.getRequestUrl(ctx.getRequest()), ^ TypeError: Cannot read properties of undefined (reading 'getRequestUrl') at AllExceptionsFilter.catch (/Users/username/Documents/workspace/project/nestjs/src/shared/filters/custom-exception.filter.ts:29:25) at ExceptionsHandler.invokeCustomFilters (/Users/username/Documents/workspace/project/nestjs/node_modules/@nestjs/core/exceptions/exceptions-handler.js:33:26) at ExceptionsHandler.next (/Users/username/Documents/workspace/project/nestjs/node_modules/@nestjs/core/exceptions/exceptions-handler.js:13:18) at /Users/username/Documents/workspace/project/nestjs/node_modules/@nestjs/core/router/router-proxy.js:13:35 at processTicksAndRejections (node:internal/process/task_queues:96:5)
相关代码
未添加try/catch的httpService调用代码
await firstValueFrom(this.httpService.post( url, { id: 'id' }, ));
AllExceptionFilter代码
import { ExceptionFilter, Catch, ArgumentsHost, HttpException, HttpStatus, } from '@nestjs/common'; import { HttpAdapterHost } from '@nestjs/core'; @Catch() export class AllExceptionsFilter implements ExceptionFilter { constructor(private readonly httpAdapterHost: HttpAdapterHost) {} catch(exception: unknown, host: ArgumentsHost): void { // In certain situations `httpAdapter` might not be available in the // constructor method, thus we should resolve it here. const { httpAdapter } = this.httpAdapterHost; const ctx = host.switchToHttp(); const httpStatus = exception instanceof HttpException ? exception.getStatus() : HttpStatus.INTERNAL_SERVER_ERROR; const responseBody = { statusCode: httpStatus, timestamp: new Date().toISOString(), path: httpAdapter.getRequestUrl(ctx.getRequest()), }; httpAdapter.reply(ctx.getResponse(), responseBody, httpStatus); } }
解决方案
方案1:修复全局异常过滤器,兼容非HTTP上下文
修改AllExceptionsFilter的catch方法,增加对HTTP上下文的有效性判断,避免在非HTTP环境下执行HTTP相关操作:
import { ExceptionFilter, Catch, ArgumentsHost, HttpException, HttpStatus, } from '@nestjs/common'; import { HttpAdapterHost } from '@nestjs/core'; @Catch() export class AllExceptionsFilter implements ExceptionFilter { constructor(private readonly httpAdapterHost: HttpAdapterHost) {} catch(exception: unknown, host: ArgumentsHost): void { const { httpAdapter } = this.httpAdapterHost; // 检查httpAdapter是否可用 if (!httpAdapter) { throw exception; } // 尝试切换到HTTP上下文 const ctx = host.switchToHttp(); const request = ctx.getRequest(); const response = ctx.getResponse(); // 验证是否为有效的HTTP请求上下文 if (!request || !response) { // 非HTTP上下文,直接抛出异常交由对应处理器处理 throw exception; } const httpStatus = exception instanceof HttpException ? exception.getStatus() : HttpStatus.INTERNAL_SERVER_ERROR; const responseBody = { statusCode: httpStatus, timestamp: new Date().toISOString(), path: httpAdapter.getRequestUrl(request), }; httpAdapter.reply(response, responseBody, httpStatus); } }
方案2:在httpService调用处主动捕获异常
在发起外部请求时主动捕获异常,避免异常冒泡到全局过滤器引发服务异常:
import { HttpException, HttpStatus } from '@nestjs/common'; import { firstValueFrom } from 'rxjs'; // ... try { await firstValueFrom(this.httpService.post( url, { id: 'id' }, )); } catch (error) { // 可根据实际需求处理错误,比如记录日志或抛出标准化业务异常 throw new HttpException('外部服务请求失败', HttpStatus.BAD_GATEWAY); }
原因分析
当httpService的请求失败抛出异常且未被捕获时,异常会被全局过滤器处理。此时若当前执行上下文并非HTTP请求上下文(或HTTP上下文已失效),ctx.getRequest()会返回undefined,同时httpAdapter可能无法正常获取,导致过滤器内部抛出未处理的类型错误,最终使NestJS服务无法继续接收新的请求。
内容的提问来源于stack exchange,提问作者tuioku
相关产品推荐
相关产品推荐

