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
相关产品推荐
相关产品推荐

