如何让NestJS控制器同时接收文件与结构化Body数据?
解决NestJS接收FormData时结构化数据扁平的问题
方法一:开启body-parser的嵌套解析支持
NestJS默认的表单解析配置不支持嵌套结构,需要在main.ts里修改urlencoded解析器配置,让它用qs库解析嵌套键值对:
import { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; import { urlencoded } from 'express'; async function bootstrap() { const app = await NestFactory.create(AppModule); // 开启extended模式,支持嵌套表单数据解析 app.use(urlencoded({ extended: true, limit: '10mb' })); await app.listen(3000); } bootstrap();
开启后,后端就能自动把policies[][library]这类扁平键转换成嵌套的数组对象结构。
方法二:配合DTO和ValidationPipe实现自动映射
先定义对应的数据结构DTO,让NestJS自动完成类型转换和验证:
// src/dtos/upload-policy.dto.ts import { IsString, IsArray } from 'class-validator'; export class PolicyItemDto { @IsString() library: string; @IsArray() @IsString({ each: true }) filesList: string[]; @IsArray() @IsString({ each: true }) ignoreList: string[]; } export class UploadDto { @IsArray() policies: PolicyItemDto[]; }
然后在全局启用ValidationPipe(也可以局部用),并在控制器中使用DTO:
// main.ts 全局启用管道 import { ValidationPipe } from '@nestjs/common'; // ... app.useGlobalPipes(new ValidationPipe({ transform: true })); // 控制器修改 @UseInterceptors(FilesInterceptor('files', 5)) @Post(Routes.UPLOAD) @HttpCode(HttpStatus.CREATED) public async upload( @CurrentUserId() userId: string, @Param('group_id') groupId: string, @Body() uploadDto: UploadDto, @UploadedFiles(new ParseFilePipe({ validators: [new PoliciesFilesValidator({})] })) files: Express.Multer.File[], ): Promise<void> { console.log(uploadDto); // 此时已转换为正常嵌套结构 await Promise.resolve(); }
transform: true会让管道自动将请求体转换成DTO实例,配合开启的extended解析,就能得到符合预期的结构化数据。
方法三:手动解析扁平数据(临时方案)
如果不想修改全局配置,可以用qs库手动解析:
先安装依赖:
npm install qs
然后在控制器内处理:
import * as qs from 'qs'; // 控制器方法内 const parsedBody = qs.parse(uploadDto as Record<string, any>); console.log(parsedBody); // 得到嵌套结构的对象
前端调整(可选优化)
可以调整object-to-formdata的序列化参数,让生成的FormData键更易被后端解析:
const finalFormData = serialize( { policies: policiesData }, // 将数组包裹在对象中 { allowEmptyArrays: true, indices: true // 生成带索引的键,如policies[0][library] }, formData );
带索引的键格式能降低后端解析的歧义,提升兼容性。
内容的提问来源于stack exchange,提问作者Tal Rofe
相关产品推荐
相关产品推荐

