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

Aar*_*lal 6 javascript node.js typescript nestjs

在使用NestJS创建API时,我想知道哪种是处理错误/异常的最佳方法。我发现了两种不同的方法:

  1. 有个别服务和验证管道throw new Error(),有控制catch他们,不是抛出适当的那种HttpExceptionBadRequestExceptionForbiddenException等..)
  2. 让控制器简单地调用负责处理业务逻辑部分的服务/验证管道方法,并抛出适当的HttpException

两种方法都各有利弊:

  1. 这似乎是正确的方法,但是,服务可以Error出于不同的原因返回,我如何从控制器中知道哪种对应的HttpException返回方式?
  2. 非常灵活,但是Http在服务中包含相关内容似乎是错误的。

我想知道,哪一种(如果有)是“嵌套js”的实现方式?

您如何处理此事?

Kim*_*ern 27

假设您的业务逻辑抛出 anEntityNotFoundError并且您想将其映射到 a NotFoundException

为此,您可以创建一个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;
        }
      }));
  }
}
Run Code Online (Sandbox Code Playgroud)

然后,您可以通过添加@UseInterceptors(NotFoundInterceptor)到控制器的类或方法中来使用它;甚至作为所有路由的全局拦截器。当然,您也可以在一个拦截器中映射多个错误。

在这个codeandbox 中尝试一下。

  • Nestjs 异常过滤器看起来更适合这项工作 https://docs.nestjs.com/exception-filters (4认同)

Ukp*_*chi 25

Nest Js提供了一个异常过滤器,可以处理应用程序层未处理的错误,因此我将其修改为返回500,即针对非Http异常的内部服务器错误。然后将异常记录到服务器,然后您就可以知道问题所在并修复它。

import 'dotenv/config';
import { ArgumentsHost, Catch, ExceptionFilter, HttpException, HttpStatus, Logger } from '@nestjs/common';

@Catch()
export class HttpErrorFilter implements ExceptionFilter {
  private readonly logger : Logger 
  constructor(){
    this.logger = new Logger 
  }
  catch(exception: Error, host: ArgumentsHost): any {
    const ctx = host.switchToHttp();
    const request = ctx.getRequest();
    const response = ctx.getResponse();

    const statusCode = exception instanceof HttpException ? exception.getStatus() : HttpStatus.INTERNAL_SERVER_ERROR
    const message = exception instanceof HttpException ?  exception.message || exception.message?.error: 'Internal server error'

    const devErrorResponse: any = {
      statusCode,
      timestamp: new Date().toISOString(),
      path: request.url,
      method: request.method,
      errorName: exception?.name,
      message: exception?.message
    };

    const prodErrorResponse: any = {
      statusCode,
      message
    };
    this.logger.log( `request method: ${request.method} request url${request.url}`, JSON.stringify(devErrorResponse));
    response.status(statusCode).json( process.env.NODE_ENV === 'development'? devErrorResponse: prodErrorResponse);
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 很好的实施!我认为您还可以使用 NestJS 依赖注入语法,因此您不必声明私有属性“logger”,然后实例化它。您可以在构造函数中使用“private readonly logger : Logger”,它会自动实例化。 (3认同)

小智 5

您可能不仅希望将服务绑定到 HTTP 接口,还希望将服务绑定到 GraphQL 或任何其他接口。因此,最好将服务中的业务逻辑级别异常转换为控制器中的 Http 级别异常(BadRequestException、ForbiddenException)。

以最简单的方式它可能看起来像

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;
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

进而