Node.js使用busboy上传文件至S3出现Unexpected end of multipart data错误如何解决
错误产生原因
- 最核心的原因是你用
async关键字修饰了路由处理函数,但函数内没有等待异步流程完成的逻辑。Serverless执行环境会判定async函数同步代码执行完毕就结束请求生命周期,不等busboy的异步事件回调执行,提前中断了请求流的传输,导致busboy底层的Dicer解析器没有收到完整的multipart数据,抛出对应错误。 - 次要可能原因:你所用的Serverless框架/网关默认开启了请求体自动解析,传递给busboy的req已经不是原始的可读流,导致流数据不完整。
- 小概率原因:前端请求未正确携带带boundary参数的
multipart/form-data请求头,或传输过程中网络中断。从你的日志已接收到完整文件chunk来看,可排除该原因。
修复方案
- 调整路由函数写法,要么移除多余的
async关键字,要么用Promise封装整个busboy解析流程,等待解析完成后再resolve,让Serverless环境等待整个流程结束再回收资源。
修改后的参考代码:
var uploadImage = (req, res) => { return new Promise((resolve, reject) => { const busboy = new Busboy({ headers: req.headers }); busboy.on('file', function (fieldname, file, filename, encoding, mimetype) { console.log('File [' + fieldname + ']: filename: ' + filename + ', encoding: ' + encoding + ', mimetype: ' + mimetype); // 实际使用时这里直接把file流pipe到S3上传实例即可,无需手动消费data // 示例:s3.upload({ Bucket: '你的bucket名', Key: filename, Body: file }).promise() file.on('data', function (data) { console.log('File [' + fieldname + '] got ' + data.length + ' bytes'); }); file.on('end', function () { console.log('File [' + fieldname + '] Finished'); }); file.on('error', reject); }); busboy.on('field', function (fieldname, val, fieldnameTruncated, valTruncated, encoding, mimetype) { console.log('Field [' + fieldname + ']: value: ' + inspect(val)); }); busboy.on('finish', function () { console.log('Done parsing form!'); res.writeHead(303, { Connection: 'close', Location: '/' }); res.end(); resolve(); }); busboy.on('error', (err) => { res.status(500).send('文件解析失败'); reject(err); }); req.pipe(busboy); }) };
- 检查Serverless网关配置,关闭默认的请求体自动解析能力,确保传递给处理函数的是原始请求流。以AWS Lambda为例,需要在API Gateway配置中添加
multipart/form-data为二进制媒体类型,关闭请求体自动解析。 - 前端不要手动设置
Content-Type请求头,让浏览器在提交FormData时自动生成带boundary参数的请求头即可。
内容的提问来源于stack exchange,提问作者D.lugade
相关产品推荐
相关产品推荐

