使用Multer上传文件至API失败,req.files为空问题求助
问题诊断与修复方案
核心问题分析
你的代码存在三个关键问题,直接导致req.files始终为空:
1. 前端手动设置请求头错误
axios发送FormData时,绝对不能手动设置Content-Type: multipart/form-data。FormData对象会自动生成包含boundary分隔符的正确请求头,手动设置会丢失这个关键信息,后端multer无法解析文件内容。
2. Multer中间件用法有误
upload.any("photos")的写法不符合规范:any()方法不需要传入字段名参数。如果要精准接收指定字段名的多个文件,应该用upload.array("photos")更合适。
3. File对象有效性存疑
如果你用URL.createObjectURL转换过文件,得到的是字符串而非原生File对象,FormData无法将其识别为文件,后端自然接收不到。必须确保photoArray中的元素是<input type="file">获取的原生File对象。
分步修复代码
前端代码修复
移除手动设置的请求头,确保photoArray元素为真实File对象:
const submitData = async () => { const token = Cookies.get("User"); if (token) { const formData = new FormData(); // 追加普通字段 formData.append("brand", currentBrand.brand); formData.append("model", currentModel); // ...其他字段保持不变 // 确保file是<input type="file">获取的原生File对象 photoArray.forEach((file) => { formData.append(`photos`, file); }); await axios .post( `http://localhost:3000/api/car/create/${ jwtDecode(token).findUser._id }`, formData // 删除手动设置的headers,axios会自动处理multipart请求头 ) .then((res) => { setSubmit(true); setTimeout(() => { setSubmit(false); }, 2000); }) .catch((err) => { setError({ state: true, message: err.response.data.message }); setTimeout(() => { setError({ state: false, message: "" }); }, 2000); }); } else { setError({ state: true, message: "Must login first" }); setTimeout(() => { setError({ state: false, message: "" }); }, 2000); } };
路由代码修复
将upload.any("photos")替换为upload.array("photos"),精准匹配前端传入的字段名:
const router = Router(); const storage = multer.diskStorage({ destination: function (req, file, cb) { cb(null, "back/uploads"); // 注意:必须提前创建back/uploads目录,multer不会自动生成目录 }, filename: function (req, file, cb) { const uniqueSuffix = Date.now() + file.originalname; cb(null, file.fieldname + "-" + uniqueSuffix); }, }); const upload = multer({ storage: storage }); // 接收指定字段"photos"的多个文件,第二个参数可设置最大上传数量(可选) router.post("/create/:id", upload.array("photos"), createCar);
额外检查项
- 确认后端项目中
back/uploads目录已创建,否则multer会因无法写入文件报错。 - 前端
photoArray的来源必须正确:如果是通过<input type="file" multiple>选择的文件,应该用event.target.files(FileList对象)转为数组,确保每个元素都是原生File对象,而非URL字符串。
验证修复
重启后端服务后测试:
- 打开浏览器Network面板,查看请求头的
Content-Type是否为multipart/form-data; boundary=xxxxxx(自动生成的分隔符)。 - 后端控制器中
console.log(req.files)会打印出上传的文件数组,包含path、filename等有效信息。
内容的提问来源于stack exchange,提问作者Tecleanu Ionut
相关产品推荐
相关产品推荐

