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

部署到Heroku后,Node.js+Multer上传图片无法正常显示求助

问题描述

我用React、Node.js、MongoDB开发了一个购物车项目,本地运行时通过Multer库将图片上传至本地文件夹。现在把Node.js部署到Heroku,MongoDB切换为云端服务后,用户及产品信息能正常存储,但图片无法正常加载。推测是云端环境无法使用本地文件夹,导致产品详情中缺失图片。

原有相关代码

config.js

const cors = require("cors");
const express = require("express");
const multer = require("multer");

const setServerConfiguration = (app) => {
    app.use(express.urlencoded({ extended: true }));
    app.use('/public',express.static("public"));
    app.use(express.json());
    app.use(cors());
  }
  const storage = multer.diskStorage({
    destination: function (req, file, cb) {
      cb(null, "./public/images/");
    },
  
    filename: function (req, file, cb) {
      cb(null, file.originalname);
    },
  });
  const upload = multer({ storage: storage });
module.exports = {setServerConfiguration, upload}

路由文件

const router = require("express").Router();
const { upload } = require("../config");
const ProductModel = require("../models/Product");
const UserModel = require("../models/User");

router.get("/", async (req, res) => {
  await UserModel.find({}, (err, obj) => {
    ProductModel.find({}, (err, obj2) => {
      const temp = [obj, obj2];
      res.json(temp);
    });
  }).clone();
});

router.post("/add-product", upload.single("product"), async (req, res) => {
  let img = req.file.filename;
  const body = req.body.product;

  await ProductModel.create({
    name: body[0],
    price: body[1],
    category: body[2],
    picture: img,
  });
  res.json("ok");
});
router.delete("/admin", async (req, res) => {
  let body = req.body.product;
  res.send(body);
  await ProductModel.deleteOne({ name: body }, (err, obj) => {});
  res.json("ok");
});
router.post("/admin", async (req, res) => {
  let price = req.body.price;
  let productName = req.body.productName;
  const filter = { name: productName };
  const update = { price: price };
  const opts = { new: true };

  await ProductModel.findOneAndUpdate(filter, update, opts);
  res.json("ok");
});

module.exports = router;

ProductModel.js

const mongoose = require("mongoose");

const ProductSchema = new mongoose.Schema({
  id : false,
    name: String,
    price: Number,
    category: String,
    picture: String,
  });

const ProductModel = mongoose.model("products", ProductSchema);
module.exports = ProductModel;
解决方案

Heroku的文件系统是临时可销毁的,服务器重启或重新部署后,本地存储的文件会全部丢失,因此不能用本地文件夹存储图片。推荐使用云存储服务托管图片,以下以Cloudinary为例给出修改步骤:

步骤1:配置Cloudinary存储

  1. 安装依赖:
npm install cloudinary multer-storage-cloudinary
  1. 创建Cloudinary配置文件(如cloudinaryConfig.js):
const cloudinary = require('cloudinary').v2;
const { CloudinaryStorage } = require('multer-storage-cloudinary');

cloudinary.config({
  cloud_name: '你的Cloudinary云名称', // 从Cloudinary控制台获取
  api_key: '你的API密钥',
  api_secret: '你的API密钥密码'
});

const storage = new CloudinaryStorage({
  cloudinary: cloudinary,
  params: {
    folder: 'product-images', // 存储图片的云端文件夹名
    allowed_formats: ['jpg', 'png', 'jpeg'],
    filename: (req, file, cb) => {
      cb(null, `${Date.now()}-${file.originalname}`); // 自定义文件名避免重复
    }
  }
});

module.exports = { storage, cloudinary };

步骤2:修改Multer配置

替换原本地存储配置,更新config.js:

const cors = require("cors");
const express = require("express");
const multer = require("multer");
const { storage } = require('./cloudinaryConfig');

const setServerConfiguration = (app) => {
    app.use(express.urlencoded({ extended: true }));
    // 不再需要托管本地public文件夹
    app.use(express.json());
    app.use(cors());
}

const upload = multer({ storage: storage });
module.exports = {setServerConfiguration, upload}

步骤3:更新产品上传接口

将数据库中存储的文件名替换为Cloudinary返回的图片URL,修改路由文件中的/add-product接口:

router.post("/add-product", upload.single("product"), async (req, res) => {
  const imgUrl = req.file.path; // 获取Cloudinary返回的图片完整URL
  const body = req.body.product;

  await ProductModel.create({
    name: body[0],
    price: body[1],
    category: body[2],
    picture: imgUrl, // 存储完整图片URL
  });
  res.json("ok");
});

步骤4:前端调整图片加载逻辑

前端直接使用数据库中存储的完整Cloudinary URL加载图片即可:

<img src={product.picture} alt={product.name} />

额外注意事项

  • 不要在代码中硬编码Cloudinary密钥,建议用dotenv管理环境变量,并在Heroku控制台配置对应环境变量
  • 若使用AWS S3、Firebase Storage等其他云存储,逻辑类似:替换Multer的存储引擎,将图片远程URL存入数据库

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 13:50:25