AWS Lambda处理multipart/form-data时图片上传S3损坏求助
解决方案
核心问题分析
- 你使用的
Buffer.from(..., 'binary')编码参数错误:API Gateway会将二进制请求体编码为base64,用'binary'解析会导致字节丢失或乱码,直接破坏图片数据。 - 用字符串正则搜索定位内容起始位置的逻辑有问题:二进制数据转字符串时会丢失原始字节结构,导致切片位置偏移,最终截取的内容不完整。
- 其他npm包返回空数组,大概率是因为你没把
event.body从base64解码为原始buffer——这类工具需要直接处理二进制multipart数据,而非base64字符串。
修正步骤
1. 先正确处理API Gateway的输入
API Gateway默认将二进制请求体编码为base64,第一步必须把event.body解码为原始buffer:
const rawBody = Buffer.from(event.body, 'base64');
2. 替换损坏的Buffer处理代码
放弃字符串操作,直接用buffer定位内容区间,修正后的核心逻辑(替代原代码中那行Buffer.from):
// 定位headers和内容的分隔符(\r\n\r\n)位置 const headerContentSeparator = part.indexOf('\r\n\r\n'); // 内容从分隔符后4个字节开始,到倒数4个字节结束(移除末尾的分隔符后缀) const contentBuffer = part.slice(headerContentSeparator + 4, part.length - 4);
注:这里的
part需要是分割后的multipart二进制buffer,若原代码中part是字符串,需先转回buffer再处理。
3. 完整修正后的解析示例
基于原有的解析逻辑重写,避免字符串操作破坏二进制数据:
function parseMultipart(event) { const boundary = extractBoundary(event.headers['Content-Type']); const rawBody = Buffer.from(event.body, 'base64'); const parts = splitMultipartBuffer(rawBody, boundary); return parts.map(part => { // 解析part的headers const headerEnd = part.indexOf('\r\n\r\n'); const headerStr = part.slice(0, headerEnd).toString('utf8'); const headers = parseHeaders(headerStr); // 获取原始内容buffer const content = part.slice(headerEnd + 4, part.length - 4); return { filename: headers['Content-Disposition']?.match(/filename="?([^"]+)"?/)?.[1], contentType: headers['Content-Type'], content: content }; }); } // 辅助函数:按分隔符分割multipart buffer function splitMultipartBuffer(buffer, boundary) { const boundaryBuffer = Buffer.from(`--${boundary}`); const parts = []; let startPos = 0; while (startPos < buffer.length) { const nextBoundaryIndex = buffer.indexOf(boundaryBuffer, startPos); if (nextBoundaryIndex === -1) break; if (nextBoundaryIndex > startPos) { parts.push(buffer.slice(startPos, nextBoundaryIndex)); } startPos = nextBoundaryIndex + boundaryBuffer.length; } return parts.filter(part => part.length > 0); } // 辅助函数:解析headers字符串 function parseHeaders(headerStr) { return headerStr.split('\r\n').reduce((acc, line) => { const [key, value] = line.split(': '); if (key) acc[key] = value; return acc; }, {}); } // 提取boundary的辅助函数 function extractBoundary(contentType) { return contentType.split('boundary=')[1]; }
4. 上传S3的注意事项
上传时直接使用解析得到的content buffer,不要额外编码,同时设置正确的Content-Type:
const s3Params = { Bucket: '你的存储桶名称', Key: '图片存储路径/xxx.jpg', Body: part.content, ContentType: part.contentType }; await s3.putObject(s3Params).promise();
其他npm包的正确用法
如果想用parse-multipart或parse-multipart-data,必须传入解码后的原始buffer:
const rawBody = Buffer.from(event.body, 'base64'); const boundary = extractBoundary(event.headers['Content-Type']); const parts = parseMultipart(rawBody, boundary); // 传buffer而非event.body
内容的提问来源于stack exchange,提问作者Sam Leurs
相关产品推荐
相关产品推荐

