如何在NestJS中同时使用platform-express与platform-fastify实现文件上传
解决方案:Fastify环境下实现NestJS文件上传
方案一:使用Fastify原生文件上传(推荐)
既然主应用基于Fastify,没必要硬套Express的multer,Fastify自身有成熟的文件上传支持,NestJS也提供了对应的适配工具。
步骤:
- 安装依赖
npm install @nestjs/platform-fastify fastify-multipart
- 在Fastify应用中注册文件上传插件
在main.ts里初始化Fastify时,注册fastify-multipart:
import { NestFactory } from '@nestjs/core'; import { FastifyAdapter, NestFastifyApplication } from '@nestjs/platform-fastify'; import { AppModule } from './app.module'; async function bootstrap() { const app = await NestFactory.create<NestFastifyApplication>( AppModule, new FastifyAdapter() ); // 注册fastify文件上传插件 await app.register(require('fastify-multipart')); await app.listen(3000); } bootstrap();
- 使用NestJS提供的Fastify文件拦截器
代替multer的FileInterceptor,使用FastifyFileInterceptor(来自@nestjs/platform-fastify):
import { Controller, Post, UploadedFile, UseInterceptors } from '@nestjs/common'; import { FastifyFileInterceptor } from '@nestjs/platform-fastify'; @Controller('upload') export class UploadController { @Post() @UseInterceptors(FastifyFileInterceptor('file')) async uploadFile(@UploadedFile() file: any) { // 处理文件逻辑,比如保存到磁盘、验证文件类型/大小 return { filename: file.filename, size: file.size, mimetype: file.mimetype }; } }
- 文件验证
可以结合class-validator和自定义管道实现验证,比如检查文件大小、类型:
import { PipeTransform, Injectable, BadRequestException } from '@nestjs/common'; @Injectable() export class FileValidationPipe implements PipeTransform { transform(file: any) { const maxSize = 1024 * 1024; // 1MB const allowedTypes = ['image/jpeg', 'image/png']; if (file.size > maxSize) { throw new BadRequestException('文件大小不能超过1MB'); } if (!allowedTypes.includes(file.mimetype)) { throw new BadRequestException('仅支持JPG/PNG格式'); } return file; } }
在路由中使用:
@Post() @UseInterceptors(FastifyFileInterceptor('file')) async uploadFile(@UploadedFile(FileValidationPipe) file: any) { // 处理文件 }
方案二:为特定路由挂载Express子应用(仅当必须用multer时)
如果你的业务逻辑严重依赖multer的现有代码,不想重写,可以创建一个独立的Express子应用,挂载到主Fastify应用的特定路由前缀下。
步骤:
- 安装Express相关依赖
npm install @nestjs/platform-express multer @types/multer
- 创建Express子应用并挂载
在main.ts中,同时初始化Fastify主应用和Express子应用,将子应用挂载到/upload路径:
import { NestFactory } from '@nestjs/core'; import { FastifyAdapter, NestFastifyApplication } from '@nestjs/platform-fastify'; import { ExpressAdapter } from '@nestjs/platform-express'; import { AppModule } from './app.module'; import { UploadModule } from './upload/upload.module'; // 你的上传模块 async function bootstrap() { // 初始化Fastify主应用 const fastifyApp = await NestFactory.create<NestFastifyApplication>( AppModule, new FastifyAdapter() ); // 初始化Express子应用,处理上传路由 const expressApp = await NestFactory.create( UploadModule, new ExpressAdapter() ); // 将Express子应用挂载到Fastify的/upload路径 fastifyApp.use('/upload', expressApp.getHttpAdapter().getInstance()); await fastifyApp.listen(3000); } bootstrap();
- 在Express子应用的模块中使用multer
在UploadModule对应的控制器中,正常使用multer的拦截器:
import { Controller, Post, UploadedFile, UseInterceptors } from '@nestjs/common'; import { FileInterceptor } from '@nestjs/platform-express'; import { diskStorage } from 'multer'; import { extname } from 'path'; @Controller() export class UploadController { @Post() @UseInterceptors(FileInterceptor('file', { storage: diskStorage({ destination: './uploads', filename: (req, file, cb) => { const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9); cb(null, file.fieldname + '-' + uniqueSuffix + extname(file.originalname)); } }), limits: { fileSize: 1024 * 1024 }, fileFilter: (req, file, cb) => { if (!file.originalname.match(/\.(jpg|png)$/)) { return cb(new Error('仅支持JPG/PNG文件'), false); } cb(null, true); } })) async uploadFile(@UploadedFile() file: Express.Multer.File) { return { filename: file.filename }; } }
方案对比
- 方案一:完全贴合Fastify生态,性能更优,避免双引擎的额外开销,是官方推荐的做法。
- 方案二:适合已有大量multer相关代码的场景,但会引入Express引擎的额外依赖,增加系统复杂度。
内容的提问来源于stack exchange,提问作者Даня Сингл
相关产品推荐
相关产品推荐

