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

NestJS从Express迁移至Fastify后Multipart表单数据(非文件JSON体)无法正常使用的技术求助

NestJS 从 Express 迁移到 Fastify 后 Multipart 表单数据(无文件)失效的解决方案

看起来你遇到的核心问题是混用了 Express 生态的 multer 中间件和 Fastify 的 fastifyMultipart 插件——Fastify 并不兼容 Express 的中间件直接通过 app.use() 挂载,这会导致 Multipart 数据解析逻辑冲突,最终让 @Body() 无法正确映射到你的 RequestDto。下面是一步步的修复方案:

1. 移除不兼容的 Express 中间件

首先删掉启动代码里的 multer 挂载行,Fastify 有自己的 Multipart 处理工具,不需要依赖 Express 的 multer:

// 删掉这行!
// app.use(multer({ dest: './public/uploads/' }).single('file'));

2. 正确配置 FastifyMultipart

调整 fastifyMultipart 的配置,确保它能把非文件字段解析并附加到请求体中,方便 @Body() 装饰器读取。如果你的接口不需要处理文件,可以直接禁用文件上传相关限制:

async function bootstrap() { 
  const { AppModule } = require('./app.module'); 
  const adapter = new FastifyAdapter({ logger: true }); 

  await adapter.register(fastifyMultipart, { 
    limits: { 
      fieldNameSize: 100, 
      fieldSize: 1000000, 
      fields: 10, 
      fileSize: 0, // 禁用文件上传(如果不需要)
      files: 0,    // 禁用文件字段
      headerPairs: 2000, 
    },
    attachFieldsToBody: true, // 关键:将非文件字段附加到 req.body
    sharedSchemaId: 'MultipartSchema', // 可选:为 Swagger 生成统一 Schema
  }); 

  const app = await NestFactory.create<NestFastifyApplication>( 
    AppModule, adapter, 
  ); 
  await app.init(); 

  // 保留 ValidationPipe,开启转换确保 DTO 映射正常
  app.useGlobalPipes(new ValidationPipe({
    transform: true,
    whitelist: true,
  })); 

  // 后续 Swagger 和启动代码保持不变
  const config = new DocumentBuilder() 
    .setTitle('Test API') 
    .setDescription('Test Identity management') 
    .setVersion('1.0') 
    .build(); 
  const document = SwaggerModule.createDocument(app, config); 
  SwaggerModule.setup('testapi', app, document); 
  await app.listen(process.env.PORT, '0.0.0.0'); 
}

3. 适配控制器的 Fastify 请求/响应对象

Fastify 的请求、响应对象和 Express 结构不同,调整控制器的类型声明,确保能正确解析数据:

import { Body, Post, Request, Response, ApiOperation, ApiResponse, ApiBody } from '@nestjs/common';
import { FastifyRequest, FastifyReply } from 'fastify';
import { RequestDto } from './your-dto-path';

@Post('/Test/V2') 
@ApiOperation({ description: '处理无文件的 Multipart 表单数据' }) 
@ApiResponse({ status: 200, description: '请求成功' })
// 可选:给 Swagger 添加 Multipart 表单的示例
@ApiBody({
  type: 'multipart/form-data',
  schema: {
    type: 'object',
    properties: {
      // 对应 RequestDto 的字段,比如:
      username: { type: 'string' },
      settings: { type: 'string', format: 'json' }, // 如果是 JSON 字符串字段
    },
  },
})
public async Test(
  @Request() req: FastifyRequest, 
  @Body() requestDto: RequestDto, 
  @Response({ passthrough: true }) response: FastifyReply
) { 
  // 现在 requestDto 应该能正确获取到表单字段了
  console.log('解析后的 DTO:', requestDto);
  
  // 你的业务逻辑...
  return response.status(200).send({ message: '处理成功' });
}

特殊场景处理:表单字段是 JSON 字符串

如果你的 Multipart 表单是把 JSON 内容放在某个单独字段里(比如 data 字段),可以手动解析并验证:

public async Test(
  @Request() req: FastifyRequest, 
  @Response({ passthrough: true }) response: FastifyReply,
  @Inject(ValidationPipe) private readonly validationPipe: ValidationPipe,
) { 
  // 从表单字段获取原始 JSON 字符串
  const rawJson = req.body.data as string;
  // 解析并验证 DTO
  const requestDto = await this.validationPipe.transform(JSON.parse(rawJson), {
    type: 'body',
    metatype: RequestDto,
  });
  
  // 业务逻辑...
}

总结

本质问题是 Fastify 和 Express 的中间件生态不兼容,移除 Express 的 multer 并正确配置 Fastify 原生的 fastifyMultipart,再适配控制器的请求响应类型,就能解决 Multipart 表单数据无法映射到 DTO 的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.01 00:22:46