NestJS 拦截器没有丰富异常处理程序

NestJS Interceptor not enriching Exception handlers

我同时使用异常过滤器、拦截器和验证管道。所有这些都按预期工作。我在全球范围内设置这些,因为这就是我现在所需要的。 AllExceptionsFilter 丰富了 NestJS 的默认异常,包括 URL、Http 方法等。 AddProgramVersionToResponseHeaderInterceptor 用于向响应添加自定义 header,其中包含我的应用程序和版本。 AppGlobalValidationPipeOptions 用于在验证错误时将 Http 状态代码从 400 转换为 422 不可处理实体。

main.ts

...
const AppHttpAdapter = app.get(HttpAdapterHost);
app.useGlobalFilters(new AllExceptionsFilter(AppHttpAdapter));
app.useGlobalInterceptors(new AddProgramVersionToResponseHeaderInterceptor());
app.useGlobalPipes(new ValidationPipe(AppGlobalValidationPipeOptions)); 
await app.listen(IpPort);

所有这些工作正常,直到我在代码中遇到异常,例如错误的路由。
GET /doesnotexist 将 return 丰富的 404 结果,这是我想要的,但是 AddProgramVersionToResponseHeader 拦截器的 Http Header 字段不会更新 header。

我已经以不同的顺序定义了全局设置,以查看是否允许拦截器添加 Http header,但这没有用。

AddProgramVersionToResponseHeader拦截器

export class AddProgramVersionToResponseHeaderInterceptor implements NestInterceptor {
    intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
        const AppInfo: ApplicationInformationService = new ApplicationInformationService();
        const EmulatorInfo: string = `${AppInfo.Name}/${AppInfo.Version}`;

        const ResponseObj: ExpressResponse = context.switchToHttp().getResponse();
        ResponseObj.setHeader('my-custom-header', EmulatorInfo);

        return next.handle().pipe();
    }
}

AllExceptionsFilter

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 HttpStatusCode: number = exception instanceof HttpException ? exception.getStatus() : HttpStatus.EXPECTATION_FAILED;
        const RequestData: string = httpAdapter.getRequestUrl(ctx.getRequest());
        const RequestURLInfo: string[] = RequestData.split('?');

        const ResponseBody: IBackendException = {
            Hostname: httpAdapter.getRequestHostname(ctx.getRequest()),
            Message: exception instanceof HttpException ? (exception.getResponse() as INestHttpException).message : [(exception as Error).message.toString()],
            Method: httpAdapter.getRequestMethod(ctx.getRequest()),
            StackTrace: exception instanceof HttpException ? '' : (exception as Error).stack,
            StatusCode: HttpStatusCode,
            Timestamp: new Date().toISOString(),
            URL: RequestURLInfo[0],
            Parameters: RequestURLInfo[1],
        };
        httpAdapter.reply(ctx.getResponse(), ResponseBody, HttpStatusCode);
    };

AppGlobalValidationPipeOptions

export const AppGlobalValidationPipeOptions: ValidationPipeOptions = {
    errorHttpStatusCode: HttpStatus.UNPROCESSABLE_ENTITY,
    transform: true,
    whitelist: true,
};

拦截器绑定到标有 HTTP 动词装饰器的路由处理程序(class 方法)。如果没有路由处理程序(如 404),则无法调用拦截器。我的 OgmaInterceptor 也有同样的问题。您可以制作一个抛出 NotFoundException@All('*') 处理程序,或者像您已经在的那样在过滤器中处理它。