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

Firebase Functions报错:Error: Unexpected end of form at Multipart._final

解决Firebase Functions中Busboy报"Unexpected end of form"错误

错误原因

这个错误的核心问题是全局启用的express.json()中间件提前解析了请求体。前端发送的是multipart/form-data格式的请求,当Busboy尝试读取原始请求数据流时,数据已经被express.json()处理过,导致数据流不完整,从而抛出"Unexpected end of form"异常。之前用multer出现同样问题,也是这个原因。

修复步骤

1. 调整express.json()的使用范围

不要全局启用express.json(),只在需要处理JSON格式请求的路由上单独添加该中间件:

修改index.js:

const functions = require('firebase-functions');
const routes = require('./src/routes/routes');
const express = require('express');
const cors = require('cors');
const app = express();
app.use(cors());

// 移除全局的express.json(),避免影响multipart请求
// app.use(express.json());

app.use('/', routes);

app.listen(3009, () => {
    console.log('Listening on 3009...'); // 代码中端口日志不一致,建议统一
});

exports.app = functions.https.onRequest(app);

如果其他路由需要处理JSON请求,可在对应路由文件中单独添加:

// 示例:其他需要JSON解析的路由文件
const express = require('express');
const router = express.Router();

// 仅对当前路由启用JSON解析
router.use(express.json());
router.post('/other-json-api', someJsonHandler);

module.exports = router;

2. 修复文件数据拼接逻辑

原代码中直接用templateBuffer = data会丢失分块传输的文件数据,需用Buffer.concat拼接所有数据块:

修改checkErrors.js中的文件处理逻辑:

bb.on('file', (fieldname, file, filename, encoding, mimetype) => {
    const chunks = [];
    file.on('data', (data) => {
        chunks.push(data);
    });
    file.on('end', () => {
        templateBuffer = Buffer.concat(chunks);
    });
});

3. 确保异步逻辑正确处理响应

用Promise包裹Busboy的处理流程,避免函数提前结束,同时捕获异常:

修改checkErrors.js整体结构:

const {TemplateHandler} = require('easy-template-x');
const handler = new TemplateHandler();
const busboy = require('busboy');

const checkErrors = (req, res) => {
    return new Promise((resolve, reject) => {
        const bb = busboy({headers: req.headers});
        let templateBuffer = null;
        let jsonData = '';

        bb.on('file', (fieldname, file, filename, encoding, mimetype) => {
            const chunks = [];
            file.on('data', (data) => {
                chunks.push(data);
            });
            file.on('end', () => {
                templateBuffer = Buffer.concat(chunks);
            });
        });

        bb.on('field', (fieldname, val) => {
            jsonData += val;
        });

        bb.on('finish', async () => {
            try {
                jsonData = JSON.parse(jsonData);
                const templateTags = await handler.parseTags(templateBuffer);
                const templateTagsNames = templateTags.map(({name}) => name);

                // 查找缺失字段逻辑
                const missingValues = [];
                jsonData
                    .filter(row => !templateTagsNames.every(name => Object.keys(row).includes(name)))
                    .forEach(row => {
                        templateTagsNames.forEach(templateName => {
                            if (!row.hasOwnProperty(templateName)) {
                                missingValues.push({fieldName: templateName, rowNum: row.rowNum + 1});
                            }
                        });
                    });

                res.json({errors: missingValues});
                resolve();
            } catch (err) {
                console.error(err);
                res.status(500).json({error: err.message});
                reject(err);
            }
        });

        bb.on('error', err => {
            console.error(err);
            res.status(400).json({error: err.message});
            reject(err);
        });

        req.pipe(bb);
    });
};

module.exports = checkErrors;

额外注意事项

  • 前端发送请求时,必须确保Content-Type为multipart/form-data,且正确构造表单数据(包含文件字段和JSON字段)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 00:42:40