NestJS - WebsocketGateway 中的 ValidationPipe 返回内部服务器错误

kam*_*myl 5 websocket typescript nestjs

我正在尝试向 NestJS 中的 WebSocketGateway 添加一些验证。这是代码:

// MessageDTO

import { IsNotEmpty, MinLength } from 'class-validator';

export class MessageDTO {
  @IsNotEmpty()
  username: string;

  @IsNotEmpty()
  @MinLength(10)
  text: string;
}
Run Code Online (Sandbox Code Playgroud)
// Gateway

import { ValidationPipe, UsePipes } from '@nestjs/common';
import { MessageBody, SubscribeMessage, WebSocketGateway, WsResponse } from '@nestjs/websockets';
import { MessageService } from './message/message.service';
import { MessageDTO } from './message/message.dto';
import { Message } from './message/message.entity';

@WebSocketGateway()
export class AppGateway {
  constructor(private readonly messageService: MessageService) {}

  @UsePipes(new ValidationPipe())
  @SubscribeMessage('message')
  async handleMessage(@MessageBody() dto: MessageDTO): Promise<WsResponse<Message>> {
    const message = await this.messageService.saveMessage(dto);
    return { event: 'message', data: message };
  }
}
Run Code Online (Sandbox Code Playgroud)

现在,当我尝试发送不符合验证规则的消息时,它会出错,但客户端总是收到{ status: 'error', message: 'Internal server error'}. 此外,Nest 将错误记录到控制台(我认为这不应该发生......?):

thing_api | Error: Bad Request Exception
thing_api |     at ValidationPipe.exceptionFactory (/usr/src/app/node_modules/@nestjs/common/pipes/validation.pipe.js:78:20)
thing_api |     at ValidationPipe.transform (/usr/src/app/node_modules/@nestjs/common/pipes/validation.pipe.js:50:24)
thing_api |     at processTicksAndRejections (internal/process/task_queues.js:89:5)
thing_api |     at async resolveParamValue (/usr/src/app/node_modules/@nestjs/websockets/context/ws-context-creator.js:104:31)
thing_api |     at async Promise.all (index 0)
thing_api |     at async pipesFn (/usr/src/app/node_modules/@nestjs/websockets/context/ws-context-creator.js:106:13)
thing_api |     at async /usr/src/app/node_modules/@nestjs/websockets/context/ws-context-creator.js:41:17
thing_api |     at async AppGateway.<anonymous> (/usr/src/app/node_modules/@nestjs/websockets/context/ws-proxy.js:11:32)
thing_api |     at async WebSocketsController.pickResult (/usr/src/app/node_modules/@nestjs/websockets/web-sockets-controller.js:85:24)
Run Code Online (Sandbox Code Playgroud)

但是,如果我在常规控制器中使用相同的 DTO 和验证管道,它就像一个魅力 - 使用格式错误的有效负载,我会收到格式正确的错误消息。有人可以指出我做错了什么吗?

Jay*_*iel 5

BadRequestException是 的子类HttpExceptionNest针对 websocket的默认异常处理程序会检查捕获的异常是否为异常instanceof WsException,如果不是则返回未知异常。

为了解决这个问题,您可以实现一个过滤器,在让 Nest 的异常过滤器处理异常之前将其捕获BadRequestException并将其转换为适当的异常。WsException

@Catch(BadRequestException)
export class BadRequestTransformationFilter extends BaseWsExceptionFilter {
  catch(exception: BadRequestException, host: ArgumentHost) {
    const properException = new WsException(exception.getResponse());
    super.catch(properException, host);
  }
}
Run Code Online (Sandbox Code Playgroud)


Z b*_*ast 5

您可以重写默认的 websocket 过滤器,以捕获 http 异常和 websocket 异常。

import { ArgumentsHost, Catch, HttpException } from '@nestjs/common';
import { WsException } from '@nestjs/websockets';
import { Socket } from 'socket.io';

@Catch(WsException, HttpException)
export class WsExceptionFilter {
  public catch(exception: HttpException, host: ArgumentsHost) {
    const client = host.switchToWs().getClient();
    this.handleError(client, exception);
  }

  public handleError(client: Socket, exception: HttpException | WsException) {
    if (exception instanceof HttpException) {
      // handle http exception
    } else {
      // handle websocket exception
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

然后在您的网关中使用它

@UseFilters(WsExceptionFilter)
@WebSocketGateway()
export class WorkspacesGateway {}
Run Code Online (Sandbox Code Playgroud)