简体   繁体   English

什么是 Nestjs 错误处理方法(业务逻辑错误与 http 错误)?

[英]What is the nestjs error handling approach (business logic error vs. http error)?

While using NestJS to create API's I was wondering which is the best way to handle errors/exception.在使用 NestJS 创建 API 时,我想知道哪种是处理错误/异常的最佳方式。 I have found two different approaches :我发现了两种不同的方法:

  1. Have individual services and validation pipes throw new Error() , have the controller catch them and then throw the appropriate kind of HttpException ( BadRequestException , ForbiddenException etc..)让单个服务和验证管道throw new Error() ,让控制器catch它们,然后抛出适当类型的HttpExceptionBadRequestExceptionForbiddenException等。)
  2. Have the controller simply call the service/validation pipe method responsible for handling that part of business logic, and throw the appropriate HttpException .让控制器简单地调用负责处理该部分业务逻辑的服务/验证管道方法,并抛出适当的HttpException

There are pros and cons to both approaches:这两种方法各有利弊:

  1. This seems the right way, however, the service can return Error for different reasons, how do I know from the controller which would be the corresponding kind of HttpException to return?这似乎是正确的方法,但是,服务可能会因不同的原因返回Error ,我如何从控制器知道哪个是相应类型的HttpException返回?
  2. Very flexible, but having Http related stuff in services just seems wrong.非常灵活,但在服务中使用Http相关的东西似乎是错误的。

I was wondering, which one (if any) is the "nest js" way of doing it?我想知道,哪一种(如果有的话)是“嵌套 js”的做法?

How do you handle this matter?你怎么处理这件事?

Let's assume your business logic throws an EntityNotFoundError and you want to map it to a NotFoundException .假设您的业务逻辑抛出EntityNotFoundError并且您希望将其映射到NotFoundException

For that, you can create an Interceptor that transforms your errors:为此,您可以创建一个Interceptor来转换您的错误:

@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;
        }
      }));
  }
}

You can then use it by adding @UseInterceptors(NotFoundInterceptor) to your controller's class or methods;然后,您可以通过将@UseInterceptors(NotFoundInterceptor)添加到控制器的类或方法中来使用它; or even as a global interceptor for all routes.甚至作为所有路由的全局拦截器。 Of course, you can also map multiple errors in one interceptor.当然,您也可以在一个拦截器中映射多个错误。

Try it out in this codesandbox .在这个codeandbox 中尝试一下。

You may want to bind services not only to HTTP interface, but also for GraphQL or any other interface.您可能不仅希望将服务绑定到 HTTP 接口,还希望绑定到 GraphQL 或任何其他接口。 So it is better to cast business-logic level exceptions from services to Http-level exceptions (BadRequestException, ForbiddenException) in controllers.因此最好将业务逻辑级别的异常从服务转换为控制器中的 Http 级别异常(BadRequestException、ForbiddenException)。

In the simpliest way it could look like以最简单的方式,它看起来像

import { BadRequestException, Injectable } from '@nestjs/common';

@Injectable()
export class HttpHelperService {
  async transformExceptions(action: Promise<any>): Promise<any> {
    try {
      return await action;
    } catch (error) {
      if (error.name === 'QueryFailedError') {
        if (/^duplicate key value violates unique constraint/.test(error.message)) {
          throw new BadRequestException(error.detail);
        } else if (/violates foreign key constraint/.test(error.message)) {
          throw new BadRequestException(error.detail);
        } else {
          throw error;
        }
      } else {
        throw error;
      }
    }
  }
}

and then进而

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM