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

从MongoDB读路径加载Public文件夹图片遇Heroku 404问题求助

问题描述

我尝试将表单上传的图片加载到首页,已在app.js中正确映射Public文件夹,图片存储路径为/public/assets/img/filename.ext。本地和AWS C9环境测试正常,但部署到Heroku staging站点时,图片出现404错误(实际文件确实存在),寻求解决建议或代码修正方案。


博客文章Schema

// schema setup
var mongoose = require("mongoose");

var postSchema = new mongoose.Schema({
    title: String,
    image: String,
    uploadedImage: {
        data: Buffer,
        contentType: String,
    },
    dest: String,
    postdata: String,
    excerpt: String,
    tag: String,
    icon: String,
    color: String,
    featured: String,
    keywords: String,
    description: String,
    slug: String,
    create: {type: Date, default: Date.now},
    author: {
      id: {
         type: mongoose.Schema.Types.ObjectId,
         ref: "User"
      },
      username: String
   },
});

module.exports = mongoose.model("Posts", postSchema);

表单提交路由

require("dotenv").config();
const   express     =   require("express"),
        router      =   express.Router(),
        Posts       =   require("../models/blog"),
        upload      =   require("../middleware/upload"),
        path        =   require('path'),
        fs          =   require('fs'),
        middleware  =   require("../middleware"),
        slugify     =   require('slugify');

// CREATE
router.post("/", middleware.isLoggedIn, middleware.isAdmin, upload.single('uploadedImage'), function(req,res){
    var title =     req.body.title;
    var image =     req.body.image;
    var postdata =  req.body.postdata;
    var exceprt =   req.body.excerpt;
    var tag =       req.body.tag;
    var icon =      req.body.icon;
    var color =     req.body.color;
    var featured =  req.body.featured;
    var keywords    = req.body.keywords;
    var description = req.body.description;
    var dest        = req.file.filename;
    var slug        = slugify(title);
    var uploadedImage = {
            data: fs.readFileSync(path.join('./public/assets/img/' + req.file.filename)),
            contentType: 'image/png'
        };
    var author = {
        id: req.user._id,
        username: req.user.username
    };
    // link dB to post values
    var newPost= {title:title, slug:slug, image:image, postdata:postdata, excerpt:exceprt, tag:tag, icon:icon, color:color, featured:featured, author:author, keywords:keywords, description:description, dest:dest, uploadedImage:uploadedImage};
    Posts.create(newPost, function(err, newlyCreated) {
        if (err){
            console.log(err);
        }else{
            console.log("slug:" + slug);
            console.log(req.file.path);
            res.redirect("/blog");
        }
    });
});

EJS图片调用代码

<% Posts.forEach(function(post){ %>
<img src="/assets/img/<%= post.dest %>" class="img-fluid" />
<% }); %>

解决建议

1. 处理Heroku临时文件系统问题

Heroku的文件系统是临时存储,应用重启(部署、休眠唤醒等)后,所有上传的本地文件会被清空。这是核心问题:你看到的“文件存在”只是当前会话的临时状态,重启后就会丢失。

  • 替代方案:改用云存储服务(如AWS S3、Cloudinary)存储上传的图片,将图片URL存入数据库,而非本地文件路径。

2. 修复路径解析问题

  • 将相对路径改为绝对路径,避免Heroku环境下路径解析错误:
    把path.join('./public/assets/img/' + req.file.filename)改为path.join(__dirname, '../public/assets/img', req.file.filename)
  • 检查upload中间件的存储配置,确保文件确实被写入到指定的public/assets/img目录。

3. 验证静态资源映射

确认app.js中的静态资源映射使用绝对路径:

app.use(express.static(path.join(__dirname, 'public')));

4. 移除不必要的数据库Buffer存储

当前代码将图片二进制数据存入uploadedImage.data,会增大数据库体积且无意义。既然已存储文件路径,可删除uploadedImage相关字段及存储逻辑,优化性能。

5. 云存储快速适配示例(以Cloudinary为例)

  • 安装依赖:npm install cloudinary multer-storage-cloudinary
  • 配置Cloudinary存储中间件,替换本地上传逻辑
  • 将Cloudinary返回的图片URL存入Post的image字段,EJS直接调用该URL即可

内容的提问来源于stack exchange,提问作者Andrew Buccellato

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 08:00:57