NestJS -WebsocketGateway中的验证管道返回内部服务器错误

vuktfyat  于 2022-11-11  发布在  其他
关注(0)|答案(5)|浏览(165)

我尝试在NestJS中为WebSocketGateway添加一些验证。代码如下:
第一个
现在,当我试图发送一个不符合验证规则的消息时,它会出错,但客户端总是会收到{ 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和验证管道,它就像一个护身符一样工作--使用格式错误的有效负载,我会得到格式正确的错误消息。有人能指出我做错了什么吗?

luaexgnf

luaexgnf1#

您可以重写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 {}
rdlzhqv9

rdlzhqv92#

BadRequestExceptionHttpException的子类。Nest的默认异常处理程序会检查捕获的异常是否为instanceof WsException,如果不是,则返回未知异常。
要解决这个问题,可以实现一个过滤器,它捕获BadRequestException并将其转换为适当的WsException,然后让Nest的异常过滤器从那里处理异常。

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

ryevplcw3#

ValidationPipe获得了exceptionFactory选项,因此您只需将自定义工厂传递给它,例如:

@UsePipes(new ValidationPipe({
    exceptionFactory(validationErrors = []) {
        if (this.isDetailedOutputDisabled) {
            return new WsException('Bad request');
        }
        const errors = this.flattenValidationErrors(validationErrors);

        return new WsException(errors);
    }
}))

或扩展内置ValidationPipe

import {Injectable, ValidationPipe} from '@nestjs/common';
import {WsException} from "@nestjs/websockets";

@Injectable()
export class WSValidationPipe extends ValidationPipe{

  createExceptionFactory() {
    return (validationErrors = []) => {
      if (this.isDetailedOutputDisabled) {
        return new WsException('Bad request');
      }
      const errors = this.flattenValidationErrors(validationErrors);

      return new WsException(errors);
    };
  }

}
t2a7ltrp

t2a7ltrp4#

我已经创建了套接字验证管道

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

anauzrmj5#

我用一个扩展transform方法的自定义类覆盖了ValidationPipetransform方法,并使用了自定义类。
它看起来像这样:

export class WSValidationPipe extends ValidationPipe {
  constructor(options?: ValidationPipeOptions) {
    super(options);
  }

  async transform(value: any, metadata: ArgumentMetadata): Promise<any> {
    try {
      return await super.transform(value, metadata);
    } catch (e: any) {
      if (e instanceof HttpException) {
        throw new WsException(e.getResponse());
      }

      throw e;
    }
  }
}

相关问题