Heroku部署应用图片上传失效,本地运行正常求助
问题描述
我开发了首个大型项目:一款支持用户撰写评论并附带图片发布的博客应用,使用Firebase存储文章。该应用在localhost运行正常,但部署到Heroku后,图片上传功能出现错误(错误截图:
)。
错误出现在editor.js文件的第8行(fetch请求处),相关代码片段如下:
uploadInput.addEventListener('change', () => { uploadImage(uploadInput, "image"); }) const uploadImage = (uploadFile, uploadType) => { const [file] = uploadFile.files; if(file && file.type.includes("image")){ const formdata = new FormData(); formdata.append('image', file); // 错误发生在这个fetch请求行 fetch('/upload', { method: 'post', body: formdata }).then(res => res.json()) .then(data => { if(uploadType == "image"){ addImage(data, file.name); } else{ bannerPath = `${location.origin}/${data}`; banner.style.backgroundImage = `url("${bannerPath}")`; } }) const change_text = document.getElementById("uploadban"); change_text.innerHTML = " "; } else{ alert("upload Image only"); } }
我怀疑问题源于将文件上传到项目目录的方式,server.js中的相关代码片段如下:
app.post('/upload', (req, res) => { let file = req.files.image; let date = new Date(); // 图片名称 let imagename = date.getDate() + date.getTime() + file.name; // 图片上传路径 let path = 'public/uploads/' + imagename; // 执行上传 file.mv(path, (err, result) => { if(err){ throw err; } else{ // 返回图片上传路径 res.json(`uploads/${imagename}`) } }) })
请问是否需要使用AWS S3这类在线存储服务来解决该问题?
问题根源
Heroku的文件系统是临时的——每次应用重启(比如部署新代码、自动扩容、Heroku定期重启),所有上传到本地目录的文件都会被清空。这就是你部署后图片上传失效的核心原因,本地运行正常是因为本地文件系统是持久化的。
解决方案
必须使用云存储服务来存储上传的图片,而不是依赖Heroku的本地文件系统。你有几个可行选择:
AWS S3/Google Cloud Storage等专业云存储
这是最通用的方案,专门用于持久化存储用户上传的文件。需要修改server.js中的上传逻辑,把文件直接上传到云存储服务,而非本地目录,之后返回云存储的文件URL给前端使用。复用已有的Firebase Storage
既然你已经在用Firebase存储文章,完全可以直接用Firebase Storage存图片。前端可直接将图片上传到Firebase Storage,再把URL关联到Firebase的文章数据;或者后端处理上传逻辑,调用Firebase SDK完成文件存储,流程更统一。Heroku第三方存储插件
Heroku市场有很多集成好的存储插件(比如Cloudinary、AWS S3官方插件),可以快速接入,减少手动配置的工作量。
为什么不能用Heroku本地存储?
Heroku的临时文件系统设计是为了保证应用的扩展性和一致性,任何写入本地的文件都不能依赖其持久化存在。即使暂时上传成功,下次应用重启后文件就会消失,用户也无法访问之前上传的图片。
代码修改方向
不管选哪种云存储,核心都是替换file.mv(path, ...)这部分逻辑:
- 不再将文件写入本地
public/uploads目录 - 改为调用对应云存储的SDK,将文件上传到云端
- 返回云端的文件URL(而非本地路径)给前端,前端直接使用该URL展示图片
内容的提问来源于stack exchange,提问作者s1mple05

