You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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ı

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 15:54:04