Node.js+Express使用Formidable上传文件时end事件提前触发问题
问题根因
你遇到的现象并非end事件提前触发,核心原因是fs.rename是异步API:
- Formidable的
end事件确实符合官方描述,会在所有文件接收并写入到临时目录完成后才触发 - 但你在
file事件回调中调用的fs.rename是异步执行的,end事件触发时,文件从临时目录移动到目标路径的操作还未完成,因此读取./data/nodes.csv会提示文件不存在。
另外注意你原代码中formidale()存在拼写错误,正确写法是formidable(),这个问题也可能导致异常。
解决方案
方案1:单文件场景适配(无额外Promise引入)
单文件上传场景下,直接把原本写在end事件里的后续逻辑,移到fs.rename的成功回调中即可,完全符合你的需求:
const fs = require('fs'); const formidable = require('formidable'); // 服务启动时提前创建data目录,避免rename报错 fs.mkdirSync('./data', { recursive: true }); app.post('/', (req, res) => { const form = formidable(); let hasFile = false; form.on('file', (filename, file) => { hasFile = true; fs.rename(file.path, `./data/nodes.csv`, err => { if (err) { console.log(`CSV文件上传出错: ${err}`); return res.status(500).send('上传失败'); } // rename完成后再执行后续逻辑 console.log("CSV文件上传成功"); console.log(fs.readFileSync('./data/nodes.csv')); const nodes = assignMetrics(); console.log(nodes); res.send(nodes); }); }); form.on('error', err => { console.log(`表单解析出错: ${err}`); res.status(500).send('解析失败'); }); form.on('end', () => { // 兜底判断未上传文件的场景 if (!hasFile) { res.status(400).send('未检测到上传文件'); } }); form.parse(req); });
方案2:多文件场景适配(无额外Promise引入)
如果后续需要扩展多文件上传,可以用计数器记录所有文件的rename操作完成状态,全部完成后再执行后续逻辑:
const fs = require('fs'); const formidable = require('formidable'); fs.mkdirSync('./data', { recursive: true }); app.post('/', (req, res) => { const form = formidable(); let totalFile = 0; let finishedFile = 0; form.on('file', (filename, file) => { totalFile++; fs.rename(file.path, `./data/${Date.now()}_${filename}`, err => { finishedFile++; if (err) { console.log(`文件${filename}移动失败: ${err}`); } // 所有文件处理完成后执行后续逻辑 if (finishedFile === totalFile) { const nodes = assignMetrics(); res.send(nodes); } }); }); form.on('error', err => { console.log(`表单解析出错: ${err}`); res.status(500).send('解析失败'); }); form.parse(req); });
内容的提问来源于stack exchange,提问作者James
相关产品推荐
相关产品推荐

