Nestjs使用multer上传文件时如何实现发邮件成功后再保存文件
实现方案
第一步:调整Multer存储配置
默认FilesInterceptor如果不传存储配置,上传的文件会暂存在内存中,刚好符合先暂存、后判断是否持久化的需求,也可以手动指定内存存储配置,避免文件提前写入持久化目录:
import { FilesInterceptor } from '@nestjs/platform-express'; import { memoryStorage } from 'multer'; @Post('upload') // 第二个参数为单次最大上传文件数量,可根据业务调整 @UseInterceptors(FilesInterceptor('files', 10, { storage: memoryStorage() }))
第二步:调整接口逻辑,先执行邮件发送再判断是否存储文件
邮件发送成功后再把内存中的文件写入持久化目录,发送失败直接返回错误即可,内存中的文件会在请求结束后自动回收,无需手动清理:
import { BadRequestException } from '@nestjs/common'; import * as fs from 'fs/promises'; import * as path from 'path'; async uploadFile(@UploadedFiles() files: Array<Express.Multer.File>) { // 替换为你自己的邮件发送业务逻辑 const isEmailSendSuccess = await yourEmailService.sendEmail(); if (!isEmailSendSuccess) { // 邮件发送失败直接抛出错误,不执行存储逻辑 throw new BadRequestException('邮件发送失败,本次上传已取消'); } // 邮件发送成功,执行文件持久化存储 const saveDir = path.join(process.cwd(), 'upload-files'); // 替换为你的正式存储目录 await fs.mkdir(saveDir, { recursive: true }); // 自动创建不存在的目录 const saveResults = []; for (const file of files) { const fileName = `${Date.now()}-${file.originalname}`; const savePath = path.join(saveDir, fileName); // 将内存中存储的文件buffer写入磁盘 await fs.writeFile(savePath, file.buffer); saveResults.push({ fileName, path: savePath, size: file.size }); } return { code: 200, message: '上传成功', data: saveResults }; }
大文件上传适配方案
如果业务支持上传大文件,内存存储会占用过多服务器资源,可以换成临时目录存储方案,邮件发送成功后把临时文件移动到正式目录,失败就删除临时文件:
// 调整Interceptor配置为临时目录存储 @UseInterceptors(FilesInterceptor('files', 10, { dest: path.join(process.cwd(), 'temp-upload') // 替换为你的临时存储目录 })) // 接口逻辑调整如下 async uploadFile(@UploadedFiles() files: Array<Express.Multer.File>) { const isEmailSendSuccess = await yourEmailService.sendEmail(); if (!isEmailSendSuccess) { // 邮件发送失败,先删除临时文件再返回错误 for (const file of files) { await fs.unlink(file.path).catch(() => {}); } throw new BadRequestException('邮件发送失败,本次上传已取消'); } const saveDir = path.join(process.cwd(), 'upload-files'); await fs.mkdir(saveDir, { recursive: true }); const saveResults = []; for (const file of files) { const fileName = `${Date.now()}-${file.originalname}`; const savePath = path.join(saveDir, fileName); // 移动临时文件到正式目录,比重新写入性能更高 await fs.rename(file.path, savePath); saveResults.push({ fileName, path: savePath, size: file.size }); } return { code: 200, message: '上传成功', data: saveResults }; }
内容的提问来源于stack exchange,提问作者Ziya Sarı
相关产品推荐
相关产品推荐

