React前端与API连接问题:CSV文件上传至MongoDB失败
React前端连接CSV上传API到MongoDB的问题排查与修复
下面是你的代码中存在的几个关键问题,以及对应的修复方案:
一、前端代码问题
- FormData未正确添加文件
你当前append的是DOM元素batch,但应该获取input的文件对象:
// 错误写法 data.append("csv-file", batch) // 正确写法 data.append("csv-file", batch.files[0])
请求URL错误
后端路由是/importStds,且index.js中已将路由挂载到根路径,所以请求地址应为http://localhost:9002/importStds,而非stdsRoute。Axios请求需确保FormData正确传递
虽然Axios会自动识别FormData并设置Content-Type,但显式声明更稳妥:
axios.post("http://localhost:9002/importStds", data, { headers: { 'Content-Type': 'multipart/form-data' } })
- 冗余参数传递
onClick={() => subBatch({})}中传递的空对象无意义,改为onClick={subBatch}即可。
修正后的前端上传函数:
const subBatch = () => { const batch = document.getElementById("bfile"); if (!batch.files.length) { alert("请选择CSV文件"); return; } const data = new FormData(); data.append("csv-file", batch.files[0]); axios.post("http://localhost:9002/importStds", data, { headers: { 'Content-Type': 'multipart/form-data' } }) .then(res => { alert(res.data.msg); }) .catch(err => { alert(err.response?.data?.msg || "上传失败"); }); };
修正后的前端表单:
<div id="batchfield"> <label for="bfile">Upload Student Info:</label> <input type="file" name="bfile" id="bfile" accept=".csv"></input> <div className="button" onClick={subBatch}>Submit</div> </div>
二、后端路由问题
未添加Multer中间件
需要在路由中添加upload.single('csv-file')中间件,用于解析上传的文件(参数需和前端FormData的字段名一致)。路由回调写法错误
当前回调未正确调用控制器函数,应直接传递控制器引用。
修正后的路由文件:
var express = require('express') const stds = express() const multer = require('multer') const path = require('path') const bodyParser = require('body-parser') stds.use(bodyParser.urlencoded({extended:true})) stds.use(express.static(path.resolve(__dirname,'public'))) var storage = multer.diskStorage({ destination:(req,file,cb) => { cb(null, './public/uploads') }, filename:(req,file,cb) =>{ cb(null, file.originalname) } }) var upload = multer({storage:storage}) const stdsController = require('../controllers/stdsC') // 修正:添加multer中间件,直接传递控制器函数 stds.post('/importStds', upload.single('csv-file'), stdsController.importStds) module.exports = stds;
三、控制器逻辑问题
异步逻辑顺序错误
csv().fromFile是异步操作,使用then会导致await Stds.insertMany在CSV解析完成前执行,此时stdsData还是空数组。应改用await来等待CSV解析完成。响应状态码设置错误
应使用res.status()来设置HTTP状态码,而非在响应体中携带status字段。
修正后的控制器文件:
var Stds = require('../models/stds') var csv = require('csvtojson') const importStds = async(req,res)=>{ try{ // 等待CSV文件解析完成 const response = await csv().fromFile(req.file.path); const stdsData = response.map(item => ({ enNo: item.EnNo, name: item.Name, sec: item.Sec, })); await Stds.insertMany(stdsData); // 设置200状态码并返回响应 res.status(200).send({success: true, msg:'Imported'}) } catch(error) { // 设置400状态码并返回错误信息 res.status(400).send({success: false, msg:error.message}) } } module.exports = importStds
额外注意事项
- 确保后端
./public/uploads目录存在,否则Multer会报错,可手动创建或在代码中添加目录检查。 - 处理跨域问题:如果前端和后端端口不同,需在后端添加CORS中间件(如
cors包),否则请求会被浏览器拦截。 - 验证CSV文件格式:可在前端或后端添加文件格式校验,确保上传的是合法的CSV文件。
内容的提问来源于stack exchange,提问作者105 Mohd. Haaris Amin
相关产品推荐
相关产品推荐

