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
相关产品推荐
相关产品推荐

