Nodejs,未知值传递给验证函数,但我找不到问题所在

pea*_*llv 11 validation node.js nestjs

感谢您过来寻求帮助。\n我有使用 NodeJs 的 API,\n它接受 3 个参数,但似乎验证存在问题。\n当我调用 API 时,它给了我这个结果,

\n\n
[{\n  "statusCode": 400,\n  "message": [\n    "an unknown value was passed to the validate function"\n  ],\n  "error": "Bad Request"\n}]\n
Run Code Online (Sandbox Code Playgroud)\n

帮助我,任何人都可以告诉我这是怎么回事!

\n

我按顺序提出了三个论点,

\n
    \n
  • https://www.youtube.com/watch?v=C5Y3fpHg45U
  • \n
  • 1
  • \n
  • JP
  • \n
\n

这是我的代码

\n
  /**\n   * Gets Subtitle From Youtube\n   * @param getYoutubeSubtitleDto\n   */\n  public async getSubtitle(\n    getYoutubeSubtitleDto: GetYoutubeSubtitleDto,\n  ): Promise<Subtitle[]> { \n    const { videoId, lang, projectId } = getYoutubeSubtitleDto\n    return this.getOrCreateSubtitles(videoId, lang, projectId)\n  }\n
Run Code Online (Sandbox Code Playgroud)\n
export class GetYoutubeSubtitleDto extends Video {\n  @ApiProperty()\n  @IsNumber()\n  @Type(() => Number)\n  projectId: number\n\n  @ApiProperty({ description: 'Translation Language' })\n  @IsString()\n  lang: string\n}\n\n
Run Code Online (Sandbox Code Playgroud)\n
export const YOUTUBE_LINK_REGEX = /http(?:s?):\\/\\/(?:www\\.)?youtu(?:be\\.com\\/watch\\?v=|\\.be\\/)([\\w\\-\\_]*)(&(amp;)?\xe2\x80\x8c\xe2\x80\x8b[\\w\\?\xe2\x80\x8c\xe2\x80\x8b=]*)?/\n\nexport class Video {\n  @ApiProperty({ description: 'Youtube Link' })\n  @IsString()\n  @Matches(YOUTUBE_LINK_REGEX)\n  video: string\n\n  public get videoId(): string { \n    return YOUTUBE_LINK_REGEX.exec(this.video)[1]\n  }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

hel*_*sor 18

将您的forbidUnknownValues标志设置为 falsemain.ts/bootstrap/useGlobalPipes

app.useGlobalPipes(
    new ValidationPipe({
      forbidUnknownValues: false
    }),
  );
Run Code Online (Sandbox Code Playgroud)


met*_*bic 18

对于任何寻求正确解决方案和解释而不仅仅是绕过错误的解决方案的人......

当您注册了全局时会发生此错误ValidationPipe

/* main.ts */
app.useGlobalPipes(new ValidationPipe())
Run Code Online (Sandbox Code Playgroud)

或本地(在端点级别):

@Post()
@UsePipes(new ValidationPipe({ transform: true }))
async save(@Query() dto: SomeDto) { ... }
Run Code Online (Sandbox Code Playgroud)

在这种情况下,NestJS 验证请求参数,如果它与指定的类型不匹配,您将收到错误消息:

“未知值被传递给验证函数”。

在大多数情况下,您的请求包含端点签名中未预期/定义的一些附加数据,或者您只是缺少有关预期作为输入类型的 DTO 或类的正确类型信息。

例如,如果控制器中有一个函数,定义如下:

@Get('/list')
async getList(@Query() dto: MyDto): Promise<List> {
  return this.listService.getList(dto);
}

// ...

class MyDto {
  @IsString()
  name: string;

  @IsString()
  surname: string;
}
Run Code Online (Sandbox Code Playgroud)

并且您将传入{name: 'A', surname: 'B', age: 42},您将收到错误,因为age预计不会传入。

有时查找这些错误可能非常耗时,一个可以帮助您解决问题的简单技巧是实现您的自定义exceptionFactory并将其传递到ValidationPipe可以打印错误的位置,其中包括一些附加元数据:

/* main.ts */
app.useGlobalPipes(new ValidationPipe({exceptionFactory: (e) => {
    console.error(e);
    throw new BadRequestException('You shall not pass!');
  }
}))
Run Code Online (Sandbox Code Playgroud)

这不会解决您的问题,但至少会告诉您哪种类型不正确,您可以从那里开始。

推荐解决方案

如果您确定传递了正确的有效负载,但不想像forbidUnknownValues其他建议那样设置,那么很可能您的一个或多个类/DTO 很可能缺少成功验证有效负载所需的一些类型声明。对我来说,大多数时候我都缺少嵌套(非原始)属性或对象数组的正确类型定义。

import {IsString, ValidateNested} from 'class-validator';
import {Type} from 'class-transformer';

//...

// Primitive type
@IsString()
name: string;

// Nested objects
@Type(() => Coach)
coach: Coach;

// Validate array of objects/entities
@ValidateNested({ each: true })
@Type(() => Player)
players: Player[];
Run Code Online (Sandbox Code Playgroud)

您可以在文档的验证章节中阅读有关请求验证的更多信息。

  • 这应该被认为是正确的解决方案 (2认同)

小智 -2

您必须将白名单forbidNonWhitelisted结合使用,

参考:

我们可以将可接受的属性列入白名单,任何未包含在白名单中的属性都会自动从结果对象中删除

或者,您可以在存在非白名单属性时停止处理请求,并向用户返回错误响应。要启用此功能,请将 forbidNonWhitelisted 选项属性设置为 true,同时将白名单设置为 true

这对我有用:

<ValidationOptions> {
  forbidNonWhitelisted: true,
  whitelist: true,
}
Run Code Online (Sandbox Code Playgroud)

NestJS这里有一个关于这个的部分。