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('*')
处理程序,或者像您已经在的那样在过滤器中处理它。
我同时使用异常过滤器、拦截器和验证管道。所有这些都按预期工作。我在全球范围内设置这些,因为这就是我现在所需要的。 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('*')
处理程序,或者像您已经在的那样在过滤器中处理它。