使用Multer获取上传文件路径/文件名时返回undefined求助
问题描述
尝试获取文件上传至文件夹后的路径或名称,但用console.log输出req.files.path或req.files.filenames时返回undefined,以下是React和Node.js代码,求解决建议。
React JS 代码
import React, { useState } from 'react'; import './Properties_Upload.css'; import Navbar from '../../../Components/Navbar/Navbar'; import Footer from '../../../Components/Footer/Footer'; import Axios from 'axios'; import { useNavigate } from 'react-router-dom'; export default function Properties_Upload() { const [addressLine, setAddressLine] = useState(''); const [addressLine2, setAddressLine2] = useState(''); const [addressCity, setAddressCity] = useState(''); const [addressState, setAddressState] = useState(''); const [addressZipCode, setAddressZipCode] = useState(''); const [mlsID, setMLSID] = useState(''); const [selectedFile, setSelectedFile] = useState([]); const [errorMessage, setErrorMessage] = useState(''); const navigate = useNavigate(); const propertyInfoHandler = () => { const url = 'http://localhost:3001/property/properties_upload'; const data = new FormData(); // 将属性信息添加到FormData data.append('addressLine', addressLine); data.append('addressLine2', addressLine2); data.append('addressCity', addressCity); data.append('addressState', addressState); data.append('addressZipCode', addressZipCode); data.append('mlsID', mlsID); // 添加文件 for (let x = 0; x < selectedFile.length; x++) { data.append('files', selectedFile[x]); } Axios.post(url, data, { headers: { 'Content-Type': 'multipart/form-data' } }) .then((response) => { navigate('/properties'); if (response.data.errorMessage){ setErrorMessage(response.data.message); } }) .catch(err => { setErrorMessage('上传失败,请重试'); console.error(err); }); }; return ( <> <Navbar /> <div className='propertiesUploadBody'> <h1>Properties Upload</h1> <div className='propertyInfoFormBody'> <h1>Property Information</h1> <p className='addressLine'> *Property address: <input name='addressLine' placeholder='Address' required autoComplete="off" onChange={(e) => setAddressLine(e.target.value)} /> </p> <p className='addressLine2'> Apartment/Suite/Unit: <input name='addressLine2' placeholder='Apartment/Suite/Unit' autoComplete="off" onChange={(e) => setAddressLine2(e.target.value)} /> </p> <p className='addressCity'> *Property city: <input name='addressCity' placeholder='City' required autoComplete="off" onChange={(e) => setAddressCity(e.target.value)} /> </p> <p className='addressState'> *Property state: <input name='addressState' placeholder='State' maxLength={2} required autoComplete="off" onChange={(e) => setAddressState(e.target.value)} /> </p> <p className='addressZipCode'> *Property zip code: <input type='number' name='addressZipCode' placeholder='Zip Code' required autoComplete="off" onChange={(e) => setAddressZipCode(e.target.value)} /> </p> <p className='propertyMLSID'> MLS ID: <input type='number' name='propertyMLSID' placeholder='MLS ID' required autoComplete="off" onChange={(e) => setMLSID(e.target.value)} /></p> </div> <div className='propertyFileFormBody'> <h1>Property Image Upload</h1> <p> Upload Images of the property.</p> <input className='uploadFiles' type='file' name='file' multiple required onChange={(e) => setSelectedFile(Array.from(e.target.files))} /> </div> <h2>{errorMessage}</h2> <button className='uploadButton' onClick={propertyInfoHandler}>Upload Property</button> </div> <Footer /> </> ) }
Node JS 代码
const express = require('express'); const router = express.Router(); const db = require('../config/db'); const bcrypt = require('bcrypt'); const saltRounds = 10; const session = require('express-session'); const bodyParser = require('body-parser'); const app = express(); const SqlDbStore = require('express-mysql-session')(session); const passport = require('passport'); const cookieParser = require('cookie-parser'); const multer = require('multer'); //----------------------------------------- BEGINNING OF PASSPORT MIDDLEWARE AND SETUP --------------------------------------------------- app.use(cookieParser()); app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: true })); app.use(passport.session()); app.use(session({ key: 'session_cookie_name', secret: 'session_cookie_secret', store: new SqlDbStore({ host: 'localhost', port: 3306, user: 'root', password: '**************', database: '**************', }), resave: false, saveUninitialized: false, cookie:{ maxAge:1000*60*60*24, secure: false } })); const multerDestination = './routes/Images/'; const storage = multer.diskStorage({ destination: function (req, file, cb) { cb(null, multerDestination); }, filename: function (req, file, cb) { cb(null, Date.now() + '-' + file.originalname ); } }); const upload = multer({ storage: storage }).array('files'); //----------------------------------------- END OF PASSPORT MIDDLEWARE AND SETUP --------------------------------------------------- router.post('/properties_upload', (req, res) => { // 修正req.body字段名,对应FormData里的键 const address = req.body.addressLine; const address2 = req.body.addressLine2; const city = req.body.addressCity; const state = req.body.addressState; const addressZipCode = req.body.addressZipCode; const mlsID = req.body.mlsID; const rentalID = Math.floor(Math.random()*90000) + 10000; upload(req, res, function (err) { if (err instanceof multer.MulterError) { return res.status(500).json(err) } else if (err) { return res.status(500).json(err) } // req.files是数组,遍历每个文件获取路径和文件名 if(req.files && req.files.length > 0) { req.files.forEach(file => { console.log("文件路径: ", file.path); console.log("文件名: ", file.filename); }); } return res.status(200).send(req.files) }); }); module.exports = router;
关键修正点
- React端:
selectedFile初始值改为数组[],将e.target.files转换为数组方便遍历处理- 将地址等属性参数添加到
FormData中,而非Axios的配置项(Axios第三个参数是请求配置,不是请求体) - 显式设置
multipart/form-data请求头,确保后端正确解析表单数据
- Node端:
- 修正
req.body字段名,与前端FormData的键对应(比如req.body.city改为req.body.addressCity) multer的diskStorage回调参数名改为file(单数),避免语义混淆req.files是数组类型,需遍历每个文件对象获取path(本地存储路径)和filename(存储后的文件名)属性
- 修正
内容的提问来源于stack exchange,提问作者JonD
相关产品推荐
相关产品推荐

