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



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

  1. throw new Error()单个服务和验证管道,让控制器catch它们,然后抛出适当的HttpException(BadRequestExceptionForbiddenException等(。
  2. 让控制器简单地调用负责处理该部分业务逻辑的服务/验证管道方法,并抛出适当的HttpException

这两种方法各有利弊:

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

我想知道,哪一个(如果有的话(是"nest js"的方式?

你是如何处理这件事的?

假设您的业务逻辑抛出了一个EntityNotFoundError,并且您希望将其映射到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;
}
}));
}
}

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

在此代码沙箱中试用一下。

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

您可能不仅希望将服务绑定到 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;
}
}
}
}

然后

您还可以使用工厂或处理程序,当控制器捕获异常(错误或域错误(时将其映射到另一个 HttpException。

@Controller('example')
export class ExampleController {
@Post('make')
async make(@Res() res, @Body() data: dataDTO): Promise<any> {

try {
//process result...
return res.status(HttpStatus.OK).json(result);
} catch (error) {
throw AppErrorHandler.createHttpException(error); //<---here is the error type mapping
};
};
};

如果您尝试发送错误的请求错误,以下代码可能会对您有所帮助:

import { Controller, Post, UploadedFiles, UseInterceptors, Body, Get } from '@nestjs/common';
import { BadRequestException } from '@nestjs/common';
import { FilesInterceptor } from '@nestjs/platform-express';

@Post('/multiple')
@UseInterceptors(FilesInterceptor('files'))
async uploadFiles(@UploadedFiles() files: Array<Express.Multer.File>, @Body() body: any) {
console.log('body :', body);
if (!files || !files.length) {
throw new BadRequestException('files should have at least one object');
}
const req: FileDataReq = {
files,
...body,
};
return req;
}

相关内容

最新更新