如何合并UseInterceptors与UploadedFile两个装饰器处理文件?
实现NestJS文件上传装饰器合并方案
要将@UseInterceptors(FileInterceptor)和@UploadedFile合并为单个参数装饰器,核心思路是自定义参数装饰器,自动为目标方法注册文件拦截器并获取上传文件。以下是具体实现步骤:
1. 自定义合并装饰器实现
创建一个参数装饰器ImageUpload,内置文件拦截器的配置逻辑,同时自动为方法添加拦截器元数据:
import { createParamDecorator, ExecutionContext, BadRequestException, Reflector } from '@nestjs/common'; import { FileInterceptor } from '@nestjs/platform-express'; import { IMAGE_COMPRESS_CONFIG } from './your-config-path'; // 替换为你的配置文件路径 const { MEGABYTE, SIZE_NUM } = IMAGE_COMPRESS_CONFIG; const reflector = new Reflector(); // 定义可选配置类型 interface ImageUploadOptions { fieldName: string; multerOptions?: Partial<import('multer').Options>; } export const ImageUpload = createParamDecorator((options: ImageUploadOptions, ctx: ExecutionContext) => { const { fieldName, multerOptions = {} } = options; const handler = ctx.getHandler(); // 检查方法是否已注册对应拦截器,避免重复添加 const existingInterceptors = reflector.get('__nest_interceptors__', handler) || []; const hasTargetInterceptor = existingInterceptors.some( (interceptorRef: any) => interceptorRef.interceptor.name === 'FileInterceptor' && interceptorRef.interceptor.options?.fieldName === fieldName ); if (!hasTargetInterceptor) { // 创建带默认配置的文件拦截器 const customInterceptor = FileInterceptor(fieldName, { limits: { fileSize: MEGABYTE * SIZE_NUM, ...multerOptions.limits }, fileFilter: (req, file, callback) => { const allowedMimeTypes = ['image/jpeg', 'image/png', 'image/jpg', 'image/webp']; if (allowedMimeTypes.includes(file.mimetype)) { callback(null, true); } else { callback(new BadRequestException('Invalid file type! Only JPG, JPEG, PNG and WebP are allowed.'), false); } }, ...multerOptions }); // 手动添加拦截器元数据到目标方法 Reflect.defineMetadata('__nest_interceptors__', [...existingInterceptors, { interceptor: customInterceptor, options: {} }], handler); } // 从请求中获取上传文件,与@UploadedFile逻辑一致 const request = ctx.switchToHttp().getRequest(); return request.file; });
2. 使用方式
直接在方法参数上使用@ImageUpload即可,无需额外添加@UseInterceptors和@UploadedFile:
基础用法
async upload(@ImageUpload({ fieldName: 'file' }) file: Express.Multer.File) { console.log(file); }
自定义配置用法
如果需要覆盖默认的文件大小、添加额外multer配置:
async upload( @ImageUpload({ fieldName: 'file', multerOptions: { limits: { fileSize: 5 * 1024 * 1024 }, // 5MB dest: './temp-uploads' } }) file: Express.Multer.File ) { console.log(file); }
实现原理
- 利用NestJS的元数据机制,在参数装饰器内部自动为目标方法注册
FileInterceptor,避免手动添加@UseInterceptors - 复用
@UploadedFile的核心逻辑,从请求对象中提取上传的文件 - 添加重复拦截器校验,避免同一方法多次注册相同拦截器导致的异常
内容的提问来源于stack exchange,提问作者Nguyễn Phan Duy
相关产品推荐
相关产品推荐

