React中使用Fetch上传Excel文件时请求体为空的问题求助
解决React Fetch上传Excel文件时Express服务器req.body为空的问题
Hey there! Let's break down why your file upload isn't working as expected and fix it step by step.
问题核心原因
Express 默认不会解析multipart/form-data格式的请求体,这就是为什么你看到req.body是空对象,且req.files也拿不到文件的原因。之前用form action能成功,是因为浏览器会自动处理表单的编码格式,而Fetch发送的请求需要服务器端专门配置中间件来解析这类数据。
解决方案步骤
1. 后端添加文件上传中间件
你原来的服务器代码里用到了req.files.avatar的写法,正好匹配express-fileupload中间件的用法,我们就用它来处理:
- 首先安装依赖:
npm install express-fileupload --save
- 然后在你的Express入口文件(比如
app.js)中配置中间件:
const express = require('express'); const fileUpload = require('express-fileupload'); const app = express(); // 启用文件上传中间件 app.use(fileUpload()); // 其他基础中间件配置 app.use(express.json()); app.use(express.urlencoded({ extended: true })); // 你的上传路由(修正后) app.post('/upload', function(req, res) { console.log(req.files); // 现在能拿到文件对象了! try { if(!req.files || !req.files.file) { // 注意和前端FormData的key保持一致,你前端用的是'file' res.send({ status: false, message: 'No file uploaded' }); } else { let excelFile = req.files.file; // 将文件移动到uploads目录 excelFile.mv('./uploads/' + excelFile.name, (err) => { if(err) { return res.status(500).send(err); } res.send({ status: true, message: 'File is uploaded', data: { name: excelFile.name, mimetype: excelFile.mimetype, size: excelFile.size } }); }); } } catch (err) { res.status(500).send(err); } })
2. 前端代码优化(可选但更规范)
你的前端代码大部分是对的,不过有几个小细节可以调整:
- 去掉
event.preventDefault():input的onChange事件不需要阻止默认行为 - 箭头函数定义的
fileHandler不需要手动bind(this),因为箭头函数会自动绑定上下文
优化后的前端代码:
class FileUploadComponent extends React.Component { fileHandler = (event) => { const fileObj = event.target.files[0]; if (!fileObj) return; // 没有选择文件时直接返回 const data = new FormData(); data.append('file', fileObj); fetch("/upload", { method: 'POST', body: data }).then(function(response) { if (response.status >= 400) { throw new Error("Bad response from server"); } return response.json(); // 建议用json解析返回值,更方便处理 }).then(function(result) { console.log("Upload success:", result); }).catch(function(err) { console.error("Upload failed:", err); }); } render() { return ( <input type="file" id="avatar" name="avatar" onChange={this.fileHandler} style={{padding: "10px"}} accept=".xlsx,.xls" // 限制只选Excel文件,提升用户体验 /> ) } }
关键注意点
- 前端不要手动设置
Content-Type: multipart/form-data:Fetch会自动添加这个请求头,并且带上正确的boundary参数,手动设置反而会导致解析失败。 - 前端FormData的key(这里是
'file')要和后端req.files[key]的key完全对应,不然会找不到文件。
内容的提问来源于stack exchange,提问作者Vaibhav Gidde
相关产品推荐
相关产品推荐

