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

Node/Express中Busboy文件上传报Unexpected end of multipart form错误排查

Busboy 文件上传报错 Unexpected end of multipart form 排查与解决

主要问题及修复方案

1. Pipe目标错误(核心问题)

你的代码最后一行错误地将请求pipe到了req.busboy,但你创建的Busboy实例是变量busboy,这导致请求数据流没有进入正确的处理逻辑,直接触发了表单结束异常。

修复代码:
将最后一行的:

req.pipe(req.busboy)

改为:

req.pipe(busboy)

2. 未监听Busboy错误事件导致应用崩溃

当前代码没有捕获Busboy的错误事件,一旦发生异常就会抛出未处理的错误导致应用崩溃。必须添加错误监听来捕获并处理异常:

添加代码:

busboy.on('error', (err) => {
  console.error('Busboy处理错误:', err);
  res.status(500).json({ error: true, message: '文件上传处理失败' });
});

3. req.body和req.files无法自动获取

Busboy不会自动将表单字段挂载到req.body,也不会把文件挂载到req.files。你需要手动监听field和file事件来收集数据,否则后续逻辑中req.body和req.files会是空值,导致业务逻辑出错。

添加字段与文件监听代码:

// 初始化表单字段存储
req.body = {};
busboy.on('field', (fieldname, value) => {
  req.body[fieldname] = value;
});

// 初始化文件存储(示例为内存存储,可根据需求调整)
req.files = {};
const concat = require('concat-stream'); // 需要先安装:npm install concat-stream

busboy.on('file', (fieldname, fileStream, filename) => {
  fileStream.pipe(concat((fileData) => {
    req.files[fieldname] = {
      name: filename,
      data: fileData,
      mimetype: fileStream.mimeType
    };
  }));
});

错误原因说明

Unexpected end of form错误通常由以下场景触发:

  • 请求数据流没有正确传入Busboy实例(比如你代码中的pipe目标错误)
  • 客户端发送的multipart表单数据不完整或被提前中断
  • Busboy没有接收到完整的表单边界标识,无法正确解析结束位置

修正后的完整代码示例

router.post('/', async (req, res) => {
    const busboy = Busboy({ headers: req.headers });
    const concat = require('concat-stream');

    // 监听Busboy错误
    busboy.on('error', (err) => {
        console.error('Busboy错误:', err);
        res.status(500).json({ error: true, message: '文件上传处理失败' });
    });

    // 收集表单字段
    req.body = {};
    busboy.on('field', (fieldname, val) => {
        req.body[fieldname] = val;
    });

    // 收集文件
    req.files = {};
    busboy.on('file', (fieldname, file, filename) => {
        file.pipe(concat((data) => {
            req.files[fieldname] = {
                name: filename,
                data: data,
                mimetype: file.mimeType
            };
        }));
    });

    busboy.on('finish', async () => {
        try {
            const { salaoId, servicos } = req.body;
            let error = [];
            let arquivos = [];

            console.log(req.files)

            if (req.files && Object.keys(req.files).length > 0) {
                for (let key of Object.keys(req.files)) {
                    const file = req.files[key];

                    const nameParts = file.name.split('.');
                    const fileName = `${new Date().getTime()}.${nameParts[nameParts.length - 1]}`;
                    const path = `servicos/${salaoId}/${fileName}`;

                    const response = await aws.uploadToS3(file, path);

                    if (response.error) {
                        error.push({ error: true, message: response.message })
                    } else {
                        arquivos.push(path)
                    }
                }
            }

            if (error.length > 0) {
                res.json(error[0]);
                return;
            }

            // 创建服务
            let jsonServico = JSON.parse(servicos);
            const servicoCadastrado = await Servicos(jsonServico).save();

            // 创建文件记录
            arquivos = arquivos.map(arquivo => ({
                referenciaId: servicoCadastrado._id,
                model: 'Servicos',
                caminho: arquivo,
            }));

            await Arquivo.insertMany(arquivos);
            res.json({ servicos: servicoCadastrado, arquivos });

        } catch (error) {
            res.json({ error: true, message: error.message })
        }
    });

    // 正确pipe到创建的busboy实例
    req.pipe(busboy);
});

module.exports = router;

内容的提问来源于stack exchange,提问作者William Berbet

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 03:31:04