【问题标题】:Interceptor not catching error thrown by guard in nestjs拦截器没有捕捉到由 Nestjs 中的守卫引发的错误
【发布时间】:2020-07-20 02:27:45
【问题描述】:

我有一个全局守卫,它在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 过滤器,但在此之前我想添加一个响应对象的标头。

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

我通过request-lifecycle了解执行上下文,并在interceptors部分找到了以下语句。

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

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

我无法弄清楚为什么拦截器没有捕获到守卫内抛出的错误。如果有人觉得需要更多信息,上面的代码 sn-ps 仅包含我认为对问题必要的部分。那我来提供。

【问题讨论】:

    标签: nestjs


    【解决方案1】:

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

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

    警卫,如下文summary 部分所述,在拦截器之前执行,因此,它们的错误无法在拦截器的catchError 方法中被捕获。您最好的选择是创建一个扩展您的 GlobalFilter 的过滤器,在其中添加您的逻辑,然后调用 super.catch(exception) 来调用其余的逻辑。

    【讨论】:

    • 感谢杰伊的回复。但我仍然不明白为什么拦截器无法捕捉到错误。
    • 拦截器及其上下文是在 守卫已经运行其canActivate 方法之后创建的。在将这些文档放在一起之前,我花了很多时间试图弄清楚何时从哪里调用方法。这只是请求生命周期的工作方式。在拦截器中,Nest 注入一个point-cut 以允许从拦截器移动到控制器,然后管理发布请求逻辑,但所有这些都发生在中间件和守卫已经执行之后。简而言之,这是框架的限制
    • Better wikipedia explains it than me,但是 TL;DR:这是一个允许根据特定情况插入其他代码的函数。在这种情况下,情况是此时此地激活了哪个类和哪个方法(即哪个控制器和哪个路由处理程序)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-31
    • 1970-01-01
    • 1970-01-01
    • 2020-05-29
    • 1970-01-01
    相关资源
    最近更新 更多