Multer上传图片报ENOENT路径错误 无法上传至Cloudinary问题咨询
问题排查:ENOENT路径报错+文件/Cloudinary上传失败
报错基础信息
- 触发场景:上传带图片的文章时Redux DevTools抛出路径不存在错误
- 程序错误访问路径:
C:\xampp\frontside\public\uploads\ - 实际正确存储路径:
C:\xampp\htdocs\mern_redux_ntv\frontside\public\uploads\ - 故障表现:目标上传文件夹无生成文件、Cloudinary端未收到任何上传资源
根因定位
一共4个叠加问题导致故障:
- Multer相对路径解析逻辑错误:配置中写的
../../frontside/public/uploads是相对路径,解析基准是Node服务启动时的命令行工作目录,而非multer配置文件自身的存放位置。当你在C:\xampp目录层级启动服务时,路径解析会直接跳转到C:\xampp\frontside\public/uploads\,和预期路径差了两层目录,直接触发ENOENT找不到目录的报错。 - Multer配置字段拼写错误:diskStorage配置中控制文件名的字段是全小写的
filename,你写成了驼峰格式fileName,Multer识别不到该配置,无法正确生成写入文件名,直接导致文件落盘失败。 - 存储路径格式非法:此前测试时配置的
http://localhost:3000/frontside/public/uploads是HTTP网络地址,不属于本地文件系统路径,Multer负责本地磁盘写入,无法识别网络地址作为存储目标。 - 前后端请求与传参逻辑错误:
- 前端上传文件时注释掉了
multipart/form-data请求头,改用application/json格式,文件对象无法被正确序列化传输,后端根本接收不到文件流 - 后端接口错误从
req.body.img取文件传给Cloudinary,经过Multer中间件处理后,上传的文件信息会挂载在req.file对象上,req.body里只存普通表单字段,拿不到文件资源自然无法上传到Cloudinary。
- 前端上传文件时注释掉了
可行修复方案
第一步:修正Multer存储配置
用Node内置path模块拼接绝对路径,彻底解决相对路径解析偏差问题,同时修正字段拼写错误:
const multer = require("multer"); const path = require("path"); const storage = multer.diskStorage({ destination: (req, file, callback) => { // 基于当前配置文件路径拼接绝对路径,不受服务启动目录影响,可自行调整../层级匹配实际目录结构 const uploadPath = path.resolve(__dirname, '../../frontside/public/uploads'); callback(null, uploadPath); }, // 修正字段名为Multer要求的全小写filename filename: (req, file, callback) => { callback(null, `${Date.now()}--${file.originalname}`); } }) const upload = multer({ storage: storage }); module.exports = upload;
注意:提前手动创建好
frontside/public/uploads目录,Multer不会自动递归生成不存在的父目录,目录不存在也会触发ENOENT报错。配置完成后可打印uploadPath变量,确认输出路径和预期的C:\xampp\htdocs\mern_redux_ntv\frontside\public\uploads\完全一致。
第二步:修正前端上传请求配置
传文件必须用FormData格式,不要手动设置Content-Type,让浏览器自动携带正确的boundary分隔参数:
const createMainNews = async (mainnewsData, token) => { // 将普通表单对象转为FormData格式 const formData = new FormData(); Object.keys(mainnewsData).forEach(key => { formData.append(key, mainnewsData[key]); }); const config = { headers: { // 禁止手动设置Content-Type,否则会丢失boundary参数导致后端解析失败 token: `Bearer ${token}`, }, } const response = await axios.post(API_URL, formData, config); console.log(response); return response.data; }
第三步:修正后端接口逻辑
从req.file获取Multer存储的本地文件路径,再传给Cloudinary上传,补全错误返回逻辑:
router.post("/", upload.single("img"), verifyTokenAndAuthorization, async (req, res) => { const { ressort, theme, title, content } = req.body; try { // 先校验文件是否上传成功 if (!req.file) { return res.status(400).json({ message: "未接收到上传的图片文件" }); } // 从req.file.path取本地存储的文件绝对路径传给Cloudinary const uploadResult = await cloudinary.uploader.upload(req.file.path, { upload_preset: "Mern_redux-practice", resource_type: "auto", }); console.log("Upload successful", JSON.stringify(uploadResult, null, 2)); // 此处可追加新闻数据入库等自定义业务逻辑 return res.status(200).json(uploadResult); } catch (error) { console.log("upload error", JSON.stringify(error, null, 2)); return res.status(500).json({ message: "上传失败", error: error.message }); } });
优化建议
如果不需要在本地留存上传文件副本,可以直接将Multer存储模式改为memoryStorage,文件会以buffer形式存在内存中,无需落盘即可直接传给Cloudinary,能彻底规避本地路径配置问题。
内容的提问来源于stack exchange,提问作者Roman
相关产品推荐
相关产品推荐

