You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

NestJS中Multipart Form Data下嵌套DTO验证失败问题

NestJS 嵌套DTO在Multipart Form Data下验证失败的解决方案

问题原因

Multipart Form Data 请求默认以键值对形式传递数据,不会自动将嵌套的JSON字符串转换为对象,而class-validator和class-transformer需要接收对象类型才能完成嵌套验证,因此出现nested property body must be either object or array的错误。

解决方案

方案一:修改DTO,手动解析JSON字符串

调整CreateHighlightDto,将body字段先按字符串接收,再通过class-transformer的Transform装饰器解析为JSON对象,同时保留嵌套验证规则:

import { Type, Transform } from 'class-transformer';
import {
  IsArray,
  IsNotEmpty,
  IsString,
  MaxLength,
  ArrayMaxSize,
  ValidateNested,
} from 'class-validator';

class CreateHighlightBody {
  @IsString()
  @MaxLength(255)
  title: string;

  @IsArray()
  @ArrayMaxSize(10)
  content: string[];

  @IsNotEmpty()
  @IsString()
  game: string;
}

export class CreateHighlightDto {
  @IsString() // 先验证是字符串格式
  @Transform(({ value }) => {
    // 解析JSON字符串为对象,添加错误处理避免解析失败
    try {
      return JSON.parse(value);
    } catch (e) {
      throw new Error('body必须是合法的JSON字符串');
    }
  })
  @ValidateNested()
  @Type(() => CreateHighlightBody)
  body: CreateHighlightBody;
}

测试传值方式

在Insomnia的Multipart Form Data表单中,body字段的值需要传入JSON格式的字符串,例如:

{"title":"测试高光","content":["击杀片段","推塔片段"],"game":"王者荣耀"}

方案二:自定义管道处理Form Data嵌套对象

如果不想修改DTO结构,可以创建自定义管道,自动解析Form Data中的嵌套字段:

import { PipeTransform, Injectable, BadRequestException } from '@nestjs/common';

@Injectable()
export class ParseNestedFormDataPipe implements PipeTransform {
  transform(value: any) {
    try {
      // 遍历字段,尝试将字符串解析为JSON对象
      Object.keys(value).forEach(key => {
        if (typeof value[key] === 'string') {
          try {
            value[key] = JSON.parse(value[key]);
          } catch {}
        }
      });
      return value;
    } catch (e) {
      throw new BadRequestException('嵌套表单数据格式无效');
    }
  }
}

控制器中使用管道

@Post('create')
@Auth()
@UseInterceptors(FileInterceptor('file'))
async create(
    @CurrentUser() user: UserCurrent,
    @Body(new ParseNestedFormDataPipe()) dto: CreateHighlightDto,
    @UploadedFile(new ParseFilePipe())
    file: Express.Multer.File
) {
    return this.highlightService.createHighlight(user, file, dto.body);
}

使用这种方式后,在Insomnia中可以直接将body字段的类型选为JSON,传入对象结构即可(部分API工具支持直接选择JSON类型传值)。

注意事项

  • 方案一中要确保传递的body是合法JSON字符串,避免解析失败;
  • 方案二的管道会尝试解析所有字符串字段,若有不需要转换的字段,可添加白名单或过滤逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 12:48:08