Javascript NestJS从ExceptionFilter抛出

Javascript NestJS从ExceptionFilter抛出,javascript,node.js,typescript,exception-handling,nestjs,Javascript,Node.js,Typescript,Exception Handling,Nestjs,我尝试使用ExceptionFilter将异常映射到它们的HTTP对应项 这是我的代码: @Catch(EntityNotFoundError) export class EntityNotFoundFilter implements ExceptionFilter { catch(exception: EntityNotFoundError, _host: ArgumentsHost) { throw new NotFoundException(exception.me

我尝试使用
ExceptionFilter
将异常映射到它们的HTTP对应项

这是我的代码:

@Catch(EntityNotFoundError)
export class EntityNotFoundFilter implements ExceptionFilter {
    catch(exception: EntityNotFoundError, _host: ArgumentsHost) {
        throw new NotFoundException(exception.message);
    }
}
但是,当执行过滤代码时,我得到了一个
未处理的PromisejectionWarning

 (node:3065) UnhandledPromiseRejectionWarning: Error: [object Object]
    at EntityNotFoundFilter.catch ([...]/errors.ts:32:15)
    at ExceptionsHandler.invokeCustomFilters ([...]/node_modules/@nestjs/core/exceptions/exceptions-handler.js:49:26)
     at ExceptionsHandler.next ([...]/node_modules/@nestjs/core/exceptions/exceptions-handler.js:13:18)
     at [...]/node_modules/@nestjs/core/router/router-proxy.js:12:35
     at <anonymous>
     at process._tickCallback (internal/process/next_tick.js:182:7)
 (node:3065) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 5)
(节点:3065)未处理的PromisejectionWarning:错误:[对象]
在EntityNotFoundFilter.catch([…]/errors.ts:32:15)
在ExceptionsHandler.invokeCustomFilters([…]/node_modules/@nestjs/core/exceptions/exceptions handler.js:49:26)
在exceptionHandler.next([…]/node_modules/@nestjs/core/exceptions/exceptions handler.js:13:18)
在[…]/node_modules/@nestjs/core/router/router proxy.js:12:35
在
在进程中。_tick回调(internal/process/next_tick.js:182:7)
(节点:3065)未处理的PromisejectionWarning:未处理的承诺拒绝。此错误源于在没有catch块的异步函数中抛出,或者拒绝未使用.catch()处理的承诺。(拒绝id:5)
我怎样才能解决这个问题

在发送响应之前,始终是最后一个被调用的位置,它负责构建响应。您不能从
ExceptionFilter
中重新显示异常

@Catch(EntityNotFoundError)
export class EntityNotFoundFilter implements ExceptionFilter {
  catch(exception: EntityNotFoundError, host: ArgumentsHost) {
    const response = host.switchToHttp().getResponse();
      response.status(404).json({ message: exception.message });
  }
}

或者,您可以创建用于转换错误的:

@Injectable()
export class NotFoundInterceptor implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    // next.handle() is an Observable of the controller's result value
    return next.handle()
      .pipe(catchError(error => {
        if (error instanceof EntityNotFoundError) {
          throw new NotFoundException(error.message);
        } else {
          throw error;
        }
      }));
  }
}
@Injectable()
导出类NotFoundInterceptor实现NestInterceptor{

拦截(context:ExecutionContext,next:CallHandler):可观察。

基于Kim Kern解决方案,我创建了这个抽象类

export abstract class AbstractErrorInterceptor<T> implements NestInterceptor {
    protected interceptedType: new (...args) => T;

    intercept(
        context: ExecutionContext,
        call$: Observable<any>,
    ): Observable<any> | Promise<Observable<any>> {
        return call$.pipe(
            catchError(exception => {
                if (exception instanceof this.interceptedType) {
                    this.handleError(exception);
                }
                throw exception;
            }),
        );
    }

    abstract handleError(exception: T);
}
导出抽象类AbstractErrorInterceptor实现NestInterceptor{
受保护的侦听类型:新(…args)=>T;
拦截(
上下文:ExecutionContext,
调用$:可观察,
):可观察的|承诺{
返回调用$.pipe(
catchError(异常=>{
if(此.interceptedType的异常实例){
此.handleError(例外);
}
抛出异常;
}),
);
}
抽象句柄错误(例外:T);
}
以及一些实现

export class EntityNotFoundFilter extends AbstractErrorInterceptor<EntityNotFoundError> {
    interceptedType = EntityNotFoundError;

    handleError(exception: EntityNotFoundError) {
        throw new NotFoundException(exception.message);
    }
}
导出类EntityNotFoundFilter扩展AbstractErrorInterceptor{
interceptedType=EntityNotFoundError;
handleError(异常:EntityNotFoundError){
抛出新的NotFoundException(exception.message);
}
}

奇怪的是,您正在创建自己版本的基于HTTP的异常类,这些异常类已经随NestJS一起提供。默认情况下,这些异常类将自动转换为带有正确错误代码的HTTP响应。您正在增加拦截器和抽象类实现的开销,而您只能抛出NestJS错误这是你提到的内置机制

抛出新的BadRequestException(“你搞错了”);

结果:

{“statusCode”:400,“错误”:“错误请求”,“消息”:“你搞错了”}


这里的关键是扩展
BaseExceptionFilter
并委托给超类,而不是抛出:

从'@nestjs/core'导入{BaseExceptionFilter};
//…你的其他进口产品
@捕获(EntityNotFoundError)
导出类EntityNotFoundFilter扩展BaseExceptionFilter{
捕获(异常:EntityNotFoundError,主机:ArgumentsHost){
super.catch(newnotfoundexception(exception.message,host));
}
}
在应用程序引导期间构造筛选器时,请确保传入
applicationRef
参数,因为
BaseExceptionFilter
需要此属性才能正确运行

从'@nestjs/core'导入{HttpAdapterHost};
//…你的其他进口产品
异步函数bootstrap():Promise{
//……诸如此类
const{httpAdapter}=app.get(HttpAdapterHost);
应用程序UseGlobalFilter(新的通用错误过滤器(httpAdapter));
//……诸如此类
}

这将导致在抛出相同错误时收到的默认错误处理。

Ok。但是手动构建响应主体似乎很奇怪。没有内置机制将异常映射到http响应?我不认为我试图以非常不寻常的方式执行某些操作。或者,您可以使用拦截器,请参阅我的edit.Set对于异常过滤器来说,响应并不罕见,但这是默认的。请看,我已经创建了一个实例供您试用:我认为在NestJS异常类已经自动转换为OP想要的相应HTTP响应时,实施所有这些仪式不是一个好的建议(re)从一开始就抛出一个嵌套选项,我假设他们知道这一点。我不创建自己版本的基于HTTP的异常类:我想使用它们!但我不想从业务代码中明确抛出基于HTTP的异常,因为这种逻辑可以在非HTTP上下文中重用(例如websocket)。我想抛出业务异常(例如,如果我检查用户的年龄是否有某些功能,则抛出UnderAgeException),然后将它们映射到Http对应项(在我们的示例中为BadRequestException)。我非常喜欢这个解决方案,因为它使用了NestJS
NotFoundException
。但我建议在转发
异常消息时要小心。根据您的查询,您可能会公开比您预期更多的内容。在我的情况下,我只是选择不提供更多详细信息。