在 NestJS 中的微服务中的异常

huangapple go评论102阅读模式
英文:

Exceptions in microservices on nestjs

问题

我有一个微服务应用程序,一个 API 网关和一个服务。RabbitMQ 用作消息代理。我意识到在服务中,需要使用带有消息和状态码的 RpcException,而不是 HttpException。但是,当在 DTO 中验证数据时使用 ValidationPipe 时,我从 API 网关得到了 500 的 statusCode。因为在底层它会抛出一个 BadRequestException。老实说,我不太明白我需要做什么来将此异常转换为 rpc 格式,或者我可能需要做其他事情。也许需要一些 exceptionFilter,但我不知道该如何做。

API 网关

  1. @Controller()
  2. export class ApiGateway {
  3. constructor(
  4. @Inject('AUTH_SERVICE') private authService: ClientProxy,
  5. ) {}
  6. @Post('auth/register')
  7. async register(
  8. @Body('email') email: string,
  9. @Body('password') password: string | number,
  10. ) {
  11. return this.authService.send({ cmd: 'register' }, { email, password });
  12. }
  13. }

main.ts auth

  1. async function bootstrap() {
  2. const app = await NestFactory.create(AuthModule);
  3. const configService = app.get(ConfigService);
  4. const rmqService = app.get(RmqService);
  5. const queue = configService.get('RABBITMQ_AUTH_QUEUE');
  6. app.connectMicroservice(rmqService.getOptions(queue));
  7. await app.startAllMicroservices();
  8. }
  9. bootstrap();

auth.controller

  1. @Controller()
  2. export class AuthController {
  3. constructor(
  4. private readonly authService: AuthService,
  5. private readonly rmqService: RmqService,
  6. ) {}
  7. @MessagePattern({ cmd: 'register' })
  8. async register(@Ctx() ctx: RmqContext, @Payload() newUser: UserDto) {
  9. this.rmqService.acknowledgeMessage(ctx);
  10. return this.authService.register(newUser);
  11. }
  12. }

UserDto

  1. @UsePipes(new ValidationPipe({ whitelist: true }))
  2. export class UserDto {
  3. @IsEmail()
  4. email: string;
  5. @IsString()
  6. @IsNotEmpty()
  7. password: string;
  8. }
英文:

I have a microservice application, an api gateway and a service. RabbitMQ is used as a message broker. I realized that in the service you need to use RpcException with message and statusCode instead of HttpException. But I ran into difficulty when using ValidationPipe when validating data in DTO, I get 500 statusCode from api gateway. Because under the hood it throws a BadRequestException. I honestly do not understand what I need to do to convert this exception to the rpc format, or maybe I need to do something else. Perhaps some kind of exceptionFilter is needed, but I do not understand how to do it.

api gateway

  1. @Controller()
  2. export class ApiGateway {
  3. constructor(
  4. @Inject('AUTH_SERVICE') private authService: ClientProxy,
  5. ) {}
  6. @Post('auth/register')
  7. async register(
  8. @Body('email') email: string,
  9. @Body('password') password: string | number,
  10. ) {
  11. return this.authService.send({ cmd: 'register' }, { email, password });
  12. }
  13. }

main.ts auth

  1. async function bootstrap() {
  2. const app = await NestFactory.create(AuthModule);
  3. const configService = app.get(ConfigService);
  4. const rmqService = app.get(RmqService);
  5. const queue = configService.get('RABBITMQ_AUTH_QUEUE');
  6. app.connectMicroservice(rmqService.getOptions(queue));
  7. await app.startAllMicroservices();
  8. }
  9. bootstrap();

auth.controller

  1. @Controller()
  2. export class AuthController {
  3. constructor(
  4. private readonly authService: AuthService,
  5. private readonly rmqService: RmqService,
  6. ) {}
  7. @MessagePattern({ cmd: 'register' })
  8. async register(@Ctx() ctx: RmqContext, @Payload() newUser: UserDto) {
  9. this.rmqService.acknowledgeMessage(ctx);
  10. return this.authService.register(newUser);
  11. }
  12. }

UserDto

  1. @UsePipes(new ValidationPipe({ whitelist: true }))
  2. export class UserDto {
  3. @IsEmail()
  4. email: string;
  5. @IsString()
  6. @IsNotEmpty()
  7. password: string;
  8. }

答案1

得分: 0

  1. export const VALIDATION_PIPE_OPTIONS = {
  2. transform: true,
  3. whitelist: true,
  4. exceptionFactory: (errors) => {
  5. return new RpcException({
  6. message: validationErrorsConversion(errors),
  7. statusCode: 400,
  8. });
  9. },
  10. };
  1. export function validationErrorsConversion(arr) {
  2. const result = [];
  3. arr.forEach((obj) => {
  4. const { property, constraints } = obj;
  5. const values = Object.keys(constraints).map(
  6. (key) => VALIDATION_ERRORS_CONST[key] || constraints[key],
  7. );
  8. result.push({
  9. [property]: values,
  10. });
  11. });
  12. return result;
  13. }
  1. export const VALIDATION_ERRORS_CONST = {
  2. isEmail: 'Is not email',
  3. isString: 'It should be a string',
  4. };
英文:

I managed to override HttpException with RpcException. I also redefined the form in which I will receive validation error messages, maybe it will be useful to someone

  1. export const VALIDATION_PIPE_OPTIONS = {
  2. transform: true,
  3. whitelist: true,
  4. exceptionFactory: (errors) => {
  5. return new RpcException({
  6. message: validationErrorsConversion(errors),
  7. statusCode: 400,
  8. });
  9. },
  10. };
  1. export function validationErrorsConversion(arr) {
  2. const result = [];
  3. arr.forEach((obj) => {
  4. const { property, constraints } = obj;
  5. const values = Object.keys(constraints).map(
  6. (key) => VALIDATION_ERRORS_CONST[key] || constraints[key],
  7. );
  8. result.push({
  9. [property]: values,
  10. });
  11. });
  12. return result;
  13. }
  1. export const VALIDATION_ERRORS_CONST = {
  2. isEmail: 'Is not email',
  3. isString: 'It should be a string',
  4. };

huangapple
  • 本文由 发表于 2023年7月10日 15:34:35
  • 转载请务必保留本文链接:https://go.coder-hub.com/76651600.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定