You need to enable JavaScript to run this app. 如何在NestJS中使用DTO实现对象数组的参数校验
优惠活动
大模型
产品
解决方案
定价
更多

如何在NestJS中使用DTO实现对象数组的参数校验

问题原因及修复方案

1. 前置依赖与全局管道配置校验

首先确保你已经安装了两个必要依赖:

npm install class-validator class-transformer

同时在main.ts中开启全局校验管道,否则DTO校验规则不会生效:

import { ValidationPipe } from '@nestjs/common';
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  // 必须添加全局校验管道,开启自动转换
  app.useGlobalPipes(new ValidationPipe({
    transform: true,
    whitelist: true
  }));
  await app.listen(3000);
}
bootstrap();

2. 核心错误修复

你当前代码存在多个结构不匹配、规则缺失的问题,是校验不生效的核心原因:

  • 提交的是直接的对象数组,但定义的PostTriviaScoreDto是包裹了items字段的对象,结构完全不匹配,校验规则无法对应到传入字段
  • 使用了ParseArrayPipe但接收参数的类型写的是单个DTO对象,不符合数组传参要求
  • answered_in_time字段只加了非空校验,没有数值类型校验,所以传入字符串也不会被拦截
  • Controller调用Service时传入了未定义的postTriviaScoreParamsDto变量,运行时会直接报错

有两种修复方向,选其中一种即可:

方向一:保留当前直接传数组的请求结构

修改post-trivia-score.dto.ts,导出内层的TriviaScore类:

import { Type } from 'class-transformer';
import { IsNotEmpty, IsUUID, IsNumber } from 'class-validator';

// 导出这个类给ParseArrayPipe使用
export class TriviaScore {
  @IsNotEmpty()
  @IsUUID()
  question_id: string;

  @IsNotEmpty()
  @IsUUID()
  selected_option_id: string;

  @IsNotEmpty()
  @IsNumber() // 新增数值类型校验
  answered_in_time: number;
}

// 可删除无用的PostTriviaScoreDto

修改trivia.controller.ts的参数配置:

import { Controller, Post, Body, ParseArrayPipe } from '@nestjs/common';
import { LoggerService } from '../logger/logger.service';
import { TriviaService } from './trivia.service';
import { TriviaScore } from './dto/post-trivia-score.dto'; // 导入TriviaScore

@Controller('trivia')
export class TriviaController {
  constructor(private readonly logger: LoggerService, private readonly triviaService: TriviaService) {}

    @Post('score')
    // items改为TriviaScore,参数类型改为数组
    postTriviaScore(@Body(new ParseArrayPipe({ items: TriviaScore })) postTriviaScoreDto: TriviaScore[]) {
        this.logger.info('Trivia Controller : postTriviaScore : start');
        // 修复未定义变量错误
        return this.triviaService.postTriviaScore(postTriviaScoreDto);
    }
}

修改trivia.service.ts的参数类型:

import { LoggerService } from '../logger/logger.service';
import { TriviaScore } from './dto/post-trivia-score.dto';

 @Injectable()
export class TriviaService {
  constructor(
    private readonly logger: LoggerService,
  ) {}
    // 参数类型改为TriviaScore数组
    postTriviaScore(allPlayersTriviaScore: TriviaScore[]) {
            this.logger.info('Trivia Service : postTriviaScore : start');
            console.log('allPlayersScore ', allPlayersTriviaScore);
    
    }
}
方向二:保留当前PostTriviaScoreDto结构

修改请求的JSON结构,在外层包裹items字段:

{
  "items": [
    {
      "question_id": "088f1344-061e-4bcc-966f-512775f1f082",
      "selected_option_id": "72305e08-fedd-49b1-adb9-1dd92c88f4db",
      "answered_in_time": 2
    }
  ]
}

同时删除ParseArrayPipe配置,直接用DTO接收即可:

// controller修改
@Post('score')
postTriviaScore(@Body() postTriviaScoreDto: PostTriviaScoreDto) {
  // 逻辑不变
}

同时给answered_in_time加上@IsNumber()校验即可。


内容的提问来源于stack exchange,提问作者Wasim

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.20 13:36:04