我正在尝试在NestJS的WebSocketGateway中添加一些验证。这是代码:
// MessageDTO
import { IsNotEmpty, MinLength } from 'class-validator';
export class MessageDTO {
@IsNotEmpty()
username: string;
@IsNotEmpty()
@MinLength(10)
text: string;
}
// 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 };
}
}
现在,当我尝试发送不符合验证规则的消息时,它会出错,但是客户端始终会收到{ 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)
但是,如果我在常规控制器中使用相同的DTO和验证管道,它的工作原理就像一个魅力-有效载荷格式错误,我会收到格式正确的错误消息。有人可以指出我在做什么错吗?
答案 0 :(得分:0)
BadRequestException
是HttpException
的子类。 Nest的默认exception handler for websockets检查所捕获的异常是否为instanceof WsException
,如果不是则返回未知异常。
要解决此问题,您可以实现一个过滤器,该过滤器可以捕获BadRequestException
并将其转换为适当的WsException
,然后再由Nest的异常过滤器处理该异常。
@Catch(BadRequestException)
export class BadRequestTransformationFilter extends BaseWsExceptionFilter {
catch(exception: BadRequestException, host: ArgumentHost) {
const properError = new WsException(exception.getResponse());
super.catch(properException, host);
}
}
答案 1 :(得分:0)
我已经创建了SocketValidation管道
import { PipeTransform, Injectable, ArgumentMetadata, ValidationPipe } from '@nestjs/common';
import { validate } from 'class-validator';
import { plainToClass } from 'class-transformer';
import { WsException } from '@nestjs/websockets';
@Injectable()
export class SocketValidationPipe implements PipeTransform<any> {
constructor() {
// super(options)
}
async transform(value: any, { metatype }: ArgumentMetadata) {
if (!metatype || !this.toValidate(metatype)) {
return value;
}
const object = plainToClass(metatype, JSON.parse(value));
const errors = await validate(object);
if (errors.length > 0) {
throw new WsException('Wrong message!');//new BadRequestException('Validation failed');
}
return value;
}
private toValidate(metatype: Function): boolean {
const types: Function[] = [String, Boolean, Number, Array, Object];
return !types.includes(metatype);
}
}
答案 2 :(得分:0)
您可以重写 the default websocket filter,以捕获 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
}
}
}
然后在您的网关中使用它
@UseFilters(WsExceptionFilter)
@WebSocketGateway()
export class WorkspacesGateway {}