首页 > 解决方案 > 拦截器没有捕捉到由 Nestjs 中的守卫引发的错误

问题描述

我有一个在应用程序中注册的全局警卫,common.module.ts它是一个全局模块。

const HeaderGuardGlobal = {
    provide: APP_GUARD,
    useClass: HeaderGuard
};

@Global()
@Module({
    imports: [ LoggerModule ],
    providers: [ HeaderGuardGlobal ],
    exports: []
})

header.guard.ts:

async canActivate(context: ExecutionContext): Promise<boolean> {
    const request = context.switchToHttp().getRequest();
    const userName = request.headers[HEADERS.USER_NAME];

    if(!userName) {
        throw new HttpException('Forbidden', HttpStatus.FORBIDDEN);
    }

我有一个控制范围的拦截器authenticate-header.interceptor.ts

@Injectable()
export class setAuthenticateHeaderInterceptor<T> implements NestInterceptor<T, Response<T>> {
    public constructor() {}

    intercept(context: ExecutionContext, next: CallHandler): Observable<Response<T>> {
        const req = context.switchToHttp().getRequest();
        const res = context.switchToHttp().getResponse();

        return next
        .handle()
        .pipe(
            catchError(err => {
                console.log('ERROR: ', err);
                    res.setHeader('sampleKey', 'sampleValue');
                    return throwError(err);
                })
            )
    }
}

user.controller.ts:

@Controller('user')
@UseInterceptors(setAuthenticateHeaderInterceptor)
export class ClientController {

我想要实现的是,当header.guard.ts抛出Forbidden异常时,authenticate-header.interceptor.ts会捕获异常并将其传播到全局 http-filter,但在此之前我想向响应对象添加一个标头。

我面临的问题是当警卫抛出异常时,拦截器无法捕获它。但是,当路由处理程序或服务抛出相同的错误时,拦截器能够捕获它。

我通过请求生命周期来了解执行上下文,并在拦截器部分找到了以下语句。

管道、控制器或服务抛出的任何错误都可以在拦截器的 catchError 运算符中读取。

该声明没有提到任何关于警卫的内容,所以我假设我想要实现的目标是不可能的。

我无法弄清楚为什么拦截器没有捕获到守卫内引发的错误。如果有人觉得需要更多信息,上面的代码片段仅包含我认为对问题必要的部分。然后我会提供它。

标签: nestjs

解决方案


正如您所提到的,文档正确地说明了,

管道、控制器或服务抛出的任何错误都可以在拦截器的 catchError 运算符中读取。

正如下面总结部分中提到的,守卫在拦截器之前执行,因此,它们的错误无法在拦截器的catchError方法中被捕获。你最好的选择是制作一个扩展你的过滤器,GlobalFilter在那里添加你的逻辑,然后调用super.catch(exception)调用其余的逻辑。


推荐阅读