Heroku部署Node.js服务时base64转文件功能报错如何解决
故障原因
代码本地运行正常、Heroku部署后失效,核心是3个代码问题+1个平台特性不匹配:
- Heroku采用临时只读文件系统:除
/tmp系统临时目录外,其余所有路径应用都没有写入权限,直接在项目工作目录写入文件会触发EACCES权限报错;且dyno重启、重新部署时/tmp外的所有文件都会被重置,平台本身也不支持在项目目录持久化存储文件。 - 同步API用法错误:
writeFileSync是同步阻塞方法,不支持传入回调函数,原有代码里写的错误回调永远不会执行,一旦写入失败错误会直接抛出,回调逻辑完全捕获不到异常。 - 未处理base64前缀:前端上传的base64通常带
data:mime;base64,格式的头,如果本地测试用的是纯base64字符串、线上传输带了前缀,转出来的Buffer会是损坏的,后续上传IPFS会直接失败。 - 异常分支资源泄漏:如果文件写入成功但后续上传IPFS报错,
unlinkSync逻辑不会执行,临时文件会残留,高并发下容易占满磁盘空间。
修复方案
最优方案(完全规避文件系统问题)
web3.storage的put方法本身支持直接传入File/Blob/Buffer对象,完全不需要先写本地文件再读取,从根源上避开Heroku的文件系统限制,性能更高:
import { File } from '@web-std/file' export const uploadFile = async(req, res) => { try { // 移除base64的data头 const pureBase64 = req.body.file.replace(/^data:.+;base64,/, '') const fileBuffer = Buffer.from(pureBase64, 'base64') // 直接构造File对象,无需落盘 const uploadFile = new File([fileBuffer], req.body.filename) const rootCid = await client.put([uploadFile]) const info = await client.status(rootCid) res.status(200).json(`${info.cid}.ipfs.dweb.link/${req.body.filename}`) } catch (error) { res.status(500).json(error) } }
兼容原有落盘逻辑的修复
如果必须走本地文件读写的流程,把文件写入路径改到系统临时目录,修正同步API的用法,加资源兜底清理:
import { writeFileSync, unlinkSync, existsSync } from 'fs' import { tmpdir } from 'os' import { join } from 'path' export const uploadFile = async(req, res) => { const pureBase64 = req.body.file.replace(/^data:.+;base64,/, '') const fileBuffer = Buffer.from(pureBase64, 'base64') // 拼接系统临时目录的文件路径,禁止写入项目工作目录 const tempFilePath = join(tmpdir(), req.body.filename) try { // 同步方法不需要传回调,错误会自动被catch捕获 writeFileSync(tempFilePath, fileBuffer) const file = await getFilesFromPath(tempFilePath) const rootCid = await client.put(file) const info = await client.status(rootCid) res.status(200).json(`${info.cid}.ipfs.dweb.link/${req.body.filename}`) } catch (error) { res.status(500).json(error) } finally { // 无论流程成功失败,都兜底删除临时文件 if (existsSync(tempFilePath)) { unlinkSync(tempFilePath) } } }
部署注意事项
- Heroku的
/tmp目录单实例有存储空间上限,单dyno临时空间通常在500MB-1GB左右,不要存储超过限制的大文件,用完必须及时清理。 - 不要依赖
/tmp目录做持久化存储,dyno每24小时会自动重启一次,重启后临时目录的所有内容都会被清空。
内容的提问来源于stack exchange,提问作者helyz247
相关产品推荐
相关产品推荐

