如何让NestJS全局异常过滤器捕获拦截器抛出的异常?
结论
可以,按照官方文档示例配置的全局异常过滤器,完全可以正常捕获拦截器抛出的所有异常,包括拦截器内部捕获原始异常后重新抛出的其他类型异常。
原理说明
NestJS 的请求处理遵循固定的分层执行链路,所有未被中途吞掉的异常都会沿着执行链路反向冒泡,最终被注册在最外层的全局异常过滤器捕获,链路顺序从外到内依次是:
- 全局中间件
- 全局守卫
- 全局拦截器(请求预处理阶段)
- 控制器级守卫、拦截器、管道
- 路由处理逻辑(服务、数据库操作等业务代码)
- 全局/控制器级拦截器(响应后处理阶段)
- 全局异常过滤器
注意:拦截器的逻辑分两个执行段,请求到达控制器前的预处理段、控制器返回结果后的响应处理段,两个阶段抛出的异常都会走统一的异常冒泡流程,不会跳过全局异常过滤器。
场景验证
举个最常见的拦截器转抛异常的例子:
@Injectable() export class ErrorTransformInterceptor implements NestInterceptor { intercept(context: ExecutionContext, next: CallHandler) { return next.handle().pipe( catchError((originErr) => { // 捕获下游抛出的原始错误,转换为自定义异常后重新抛出 throw new CustomBizException({ code: originErr.status || 500, message: `拦截器处理异常: ${originErr.message}` }) }) ) } }
上述代码里拦截器重新抛出的CustomBizException,会和控制器、服务层直接抛出的异常一样,被全局异常过滤器正常识别、匹配、处理,没有任何差异。
捕获失败的常见原因
如果遇到全局过滤器没抓到拦截器异常的情况,基本都是以下两个问题导致的:
- 拦截器内部吞掉了异常:比如
catchError回调里直接返回了固定默认值,没有抛出错误也没有返回throwError,异常终止传播自然到不了过滤器 - 过滤器注册作用域错误:通过
app.useGlobalFilters()在bootstrap阶段注册的过滤器是真正的应用全局级,一定能捕获;如果是通过模块内APP_FILTER令牌注册的过滤器,只有注册在根模块时才是全局作用域,注册在子模块的话作用域仅覆盖子模块内的路由,会出现捕获不到的情况。
内容的提问来源于stack exchange,提问作者RinnieR
相关产品推荐
相关产品推荐

