Heroku无法创建临时文件,求NextJS上传AWS S3的可行方案
解决方案:Heroku Next.js API应用上传文件到AWS S3
一、修复临时文件创建问题(针对CSV场景)
Heroku的临时文件系统仅/tmp目录支持可写操作(dyno重启会清空,但上传完成后文件无保留必要),你之前的问题大概率是路径或操作逻辑问题,调整方案如下:
- 固定使用
/tmp目录
Next.js的public目录在Heroku部署后为只读状态,必须切换到/tmp。修改路径生成逻辑:
const tempDir = '/tmp/csv-storage'; // 递归创建目录,无需担心层级不存在 await fs.promises.mkdir(tempDir, { recursive: true, mode: '0o755' }); // 生成标准化文件名 const fileName = `${new Date().toISOString().split('T')[0]}.csv`; const filePath = `${tempDir}/${fileName}`;
- 优化文件操作逻辑
避免重复拼接路径,改用异步方法适配Next.js API环境(同步方法易阻塞事件循环):
try { // 检查文件是否存在,不存在会抛出错误进入catch分支 await fs.promises.access(filePath); // 文件存在则追加内容 await fs.promises.appendFile(filePath, await csv.toString(false), 'utf-8'); } catch (err) { // 文件不存在则新建 await fs.promises.writeFile(filePath, await csv.toString(true)); }
- 验证文件创建状态
可添加日志确认操作结果,通过heroku logs --tail查看:
const stats = await fs.promises.stat(filePath); console.log(`临时文件创建成功,大小:${stats.size}字节`);
二、无需落地文件,直接上传到S3(推荐方案)
跳过本地文件创建步骤,直接将内存中的数据上传到S3,既提升效率又规避文件系统问题:
针对CSV文件
AWS SDK支持直接上传字符串或Buffer,步骤如下:
- 安装依赖(未安装时执行):
npm install @aws-sdk/client-s3
- 直接上传CSV内容:
import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3'; // 初始化S3客户端(从环境变量读取配置) const s3Client = new S3Client({ region: process.env.AWS_REGION, credentials: { accessKeyId: process.env.AWS_ACCESS_KEY_ID, secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY, }, }); // 直接使用csv生成的字符串上传 const csvContent = await csv.toString(true); // 根据业务逻辑切换toString参数 const uploadParams = { Bucket: process.env.S3_BUCKET_NAME, Key: `${new Date().toISOString().split('T')[0]}.csv`, Body: csvContent, ContentType: 'text/csv', }; try { await s3Client.send(new PutObjectCommand(uploadParams)); console.log('CSV文件上传S3成功'); } catch (err) { console.error('S3上传失败:', err); }
针对PNG图片
如果是处理PNG数据(如请求中接收的图片),直接上传Buffer即可:
// 示例:从请求中获取图片Buffer(根据实际请求逻辑调整) const imageBuffer = req.file.buffer; const uploadParams = { Bucket: process.env.S3_BUCKET_NAME, Key: `images/${Date.now()}.png`, Body: imageBuffer, ContentType: 'image/png', }; await s3Client.send(new PutObjectCommand(uploadParams));
核心注意事项
- Heroku仅
/tmp目录支持可写,不要尝试使用其他路径(如根目录、public目录),均为只读状态。 - 优先使用异步文件操作,避免同步方法阻塞Next.js事件循环。
- 直接上传内存数据到S3是最优方案,省去文件IO步骤,彻底规避临时文件相关问题。
内容的提问来源于stack exchange,提问作者Ouchou Ayoub
相关产品推荐
相关产品推荐

