NestJS如何在请求体无文件时绕过FileInterceptor拦截器?
解决NestJS中SMTP邮件队列服务支持带/不带附件的问题
方案1:让FileInterceptor兼容无附件请求
直接给FileInterceptor添加fileIsRequired: false配置,同时用@Optional()标记文件参数,允许请求中不带file字段:
import { Controller, Post, UploadedFile, UseInterceptors, Optional, Body } from '@nestjs/common'; import { FileInterceptor } from '@nestjs/platform-express'; @Controller('mail') export class MailController { @Post('send') @UseInterceptors(FileInterceptor('file', { fileIsRequired: false // 允许请求中没有file字段 })) async sendMail( @Body() mailDto: MailDto, @Optional() @UploadedFile() file?: Express.Multer.File // 标记参数为可选 ) { // 业务逻辑:存在file则添加附件,否则发送普通邮件 const queueData = file ? { ...mailDto, attachment: file } : mailDto; return await this.mailQueueService.addToQueue(queueData); } }
注意:这个配置需要NestJS @nestjs/platform-express 版本在8.0及以上,低版本可能不支持fileIsRequired参数。
方案2:拆分两个独立接口
如果不想调整拦截器,直接拆成两个接口分别处理:
- 无附件邮件:不需要文件拦截器,直接接收JSON参数
- 带附件邮件:使用
FileInterceptor处理文件上传
@Controller('mail') export class MailController { // 发送无附件邮件 @Post('send') async sendPlainMail(@Body() mailDto: MailDto) { return await this.mailQueueService.addToQueue(mailDto); } // 发送带附件邮件 @Post('send-with-attachment') @UseInterceptors(FileInterceptor('file')) async sendMailWithAttachment( @Body() mailDto: MailDto, @UploadedFile() file: Express.Multer.File ) { return await this.mailQueueService.addToQueue({ ...mailDto, attachment: file }); } }
方案3:自定义可选文件拦截器
如果需要统一接口,可自定义拦截器自动判断请求是否带文件:
import { Injectable, NestInterceptor, ExecutionContext, CallHandler, mixin } from '@nestjs/common'; import { FileInterceptor } from '@nestjs/platform-express'; import { Observable } from 'rxjs'; export function OptionalFileInterceptor(fieldName: string) { class Interceptor implements NestInterceptor { async intercept(context: ExecutionContext, next: CallHandler): Promise<Observable<any>> { const request = context.switchToHttp().getRequest(); // 判断请求中是否包含目标文件字段 const hasFile = request.headers['content-type']?.includes('multipart/form-data') && request.files?.[fieldName]; if (!hasFile) { return next.handle(); } // 有文件时用原生FileInterceptor处理 const fileInterceptor = new (FileInterceptor(fieldName))(); return fileInterceptor.intercept(context, next); } } return mixin(Interceptor); }
控制器中使用自定义拦截器:
@Post('send') @UseInterceptors(OptionalFileInterceptor('file')) async sendMail( @Body() mailDto: MailDto, @UploadedFile() file?: Express.Multer.File ) { // 业务逻辑同上 }
内容的提问来源于stack exchange,提问作者Châu Phước Thịnh
相关产品推荐
相关产品推荐

