React结合Multer上传图片失败:图片未存入指定文件夹
React上传图片至Multer配置的Node.js服务器失败问题排查
我正尝试通过React向配置了Multer的Node.js服务器上传图片,已在前端调用API,后端完成Multer配置,但代码无法正常运行,图片并未上传至指定文件夹。请帮忙排查问题。
前端React代码
import React, { useEffect, useState, useRef } from 'react'; import { Router, useNavigate } from 'react-router-dom'; import axios from "axios"; const Dashboard = () => { const [userName, userNameSetter] = useState(""); const [userEmail, userEmailSetter] = useState(""); const [artTitle, setArtTitle] = useState(""); const [artContent, setArtContent] = useState(""); const [imagePreview, setPreview] = useState(undefined); const [imageToSend, setImageToSend] = useState(undefined); const fileUploadRef = useRef(null); async function makePost(e) { // 修复拼写错误:preventdefault -> preventDefault e.preventDefault(); console.log("触发上传函数"); const fd = new FormData(); // 修复:传入原始文件对象而非本地预览URL fd.append("form-image", imageToSend); try { // 修复:直接传递FormData,配置正确请求头 const response = await axios.post( "http://localhost:1337/api/multer-photo-upload", fd, { headers: { 'Content-Type': 'multipart/form-data' } } ); console.log(response); } catch (error) { console.error("上传失败:", error); } } const addPostImage = () => { fileUploadRef.current.click(); }; async function uploadPostImage(e) { if (e.target.files.length === 0) { console.log("请选择一张图片"); } else { const imageFile = e.target.files[0]; const imageMain = URL.createObjectURL(imageFile); setPreview(imageMain); // 修复:存储文件对象而非预览URL setImageToSend(imageFile); } } async function performUpload(fd) {} // 修复:添加依赖数组,避免不必要的重复执行 useEffect(() => { let emailAdd = localStorage.getItem("email"); let uName = localStorage.getItem("name"); userNameSetter(uName); userEmailSetter(emailAdd); }, []); return ( <> <Header /> <section className='dashboard-wrapper'> <section className='dashboard-left'> <center><h1>CW ADMIN DASHBOARD</h1></center> <center> <span className='u-av'> <i className="ri-user-fill"></i> </span> <h3> Welcome {userName}. <br />Your Email is {userEmail} </h3> </center> </section> <section className='dashboard-right'> <h3>UPLOAD AN ARTICLE</h3> <form action='' enctype='multipart/form-data' name='upload-article-form'> <input type='text' placeholder='Article Title' className='art-title' onChange={(e) => setArtTitle(e.target.value)} /><br /> <textarea placeholder='Article Content' className='art-content' onChange={(e) => setArtContent(e.target.value)} ></textarea><br /> <div className='image-preview'> {imagePreview && <img src={imagePreview} style={{ maxWidth: "200px" }} />} </div> <input type='button' value='Add Image' onClick={addPostImage} /> <input type='file' name='image' id="img-upload" className='img-upload' ref={fileUploadRef} onChange={uploadPostImage} /> <input type='submit' value='Upload' onClick={makePost} /> </form> </section> </section> <WhiteFooter /> </> ); }; export default Dashboard;
后端Node.js代码
const express = require("express"); const app = express(); const cors = require("cors"); const User = require('./models/user.model.js'); const fs = require("fs"); const path = require("path"); const multer = require("multer"); // 修复:使用绝对路径,确保上传目录存在 const uploadPath = path.resolve(__dirname, "../carefu_watchers/src/uploads/"); // 自动创建不存在的上传目录 if (!fs.existsSync(uploadPath)) { fs.mkdirSync(uploadPath, { recursive: true }); } const storage = multer.diskStorage({ destination: (req, file, cb) => { cb(null, uploadPath); }, filename: (req, file, cb) => { console.log(file); cb(null, Date.now() + path.extname(file.originalname)); } }); const uploadImage = multer({ storage: storage, // 可选:添加文件类型过滤,仅允许图片上传 fileFilter: (req, file, cb) => { const allowedTypes = /jpeg|jpg|png|gif/; const extname = allowedTypes.test(path.extname(file.originalname).toLowerCase()); const mimetype = allowedTypes.test(file.mimetype); if (extname && mimetype) { return cb(null, true); } else { cb(new Error("仅支持JPG/PNG/GIF格式的图片")); } } }); // 修复:启用CORS中间件,允许跨域请求 app.use(cors()); app.use(express.json()); // 修复:添加错误处理,明确上传状态 app.post("/api/multer-photo-upload", uploadImage.single("form-image"), (req, res) => { if (!req.file) { return res.status(400).send("未接收到上传文件"); } console.log("文件上传成功:", req.file); res.send("文件上传成功"); }, (error, req, res, next) => { res.status(400).send(error.message); }); app.listen(1337, () => { console.log("服务器启动于端口1337"); });
关键错误点总结
前端:
- 表单提交事件方法拼写错误:
e.preventdefault()→e.preventDefault(),导致页面默认刷新中断请求 - 存储错误的数据:将预览URL存入状态而非原始文件对象,导致FormData无法正确传递文件
- axios请求参数错误:将FormData包裹在对象中传递,后端无法解析,需直接传入FormData并配置请求头
- useEffect缺少依赖数组,导致组件重复渲染时重复执行逻辑
- 表单提交事件方法拼写错误:
后端:
- 未启用CORS中间件,跨域请求被浏览器拦截
- 上传路径使用相对路径,可能因服务器启动目录不同导致路径错误,需改用绝对路径并确保目录存在
- 缺少错误处理逻辑,无法排查上传失败的具体原因
内容的提问来源于stack exchange,提问作者Eluan David Harold
相关产品推荐
相关产品推荐

