You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 14:30:01