Node.js+XLSX实现XLSX转JSON:浏览器上传数据乱码求助
问题排查与解决方案
核心问题分析
浏览器上传后乱码、CloudWatch日志显示form-data头混入数据区,而Postman测试正常,本质是浏览器端上传的multipart/form-data请求未被正确解析,导致Lambda收到的不是纯文件二进制内容,而是包含表单边界、字段头的完整表单数据。Postman会自动处理multipart/form-data的边界和编码,因此能正常触发流程。
分步排查与修复
1. 前端上传代码问题(最常见)
如果前端手动设置了Content-Type: multipart/form-data,会导致浏览器无法自动添加表单边界参数,API Gateway无法识别并解析多部分数据。
错误示例:
const formData = new FormData(); formData.append('file', fileInput.files[0]); fetch(apiGatewayUrl, { method: 'POST', headers: { 'Content-Type': 'multipart/form-data' // 手动设置会导致边界丢失 }, body: formData });
修复:
移除手动设置的Content-Type,让浏览器自动生成带边界的请求头:
const formData = new FormData(); formData.append('file', fileInput.files[0]); fetch(apiGatewayUrl, { method: 'POST', body: formData // 浏览器会自动添加正确的Content-Type及边界 });
2. API Gateway配置问题
即使开启了二进制媒体类型,若映射模板未正确解析multipart/form-data,仍会把完整表单数据传给Lambda。
配置步骤:
- 添加二进制媒体类型:在API Gateway控制台的「设置」中,添加
multipart/form-data到二进制媒体类型列表。 - 配置集成请求映射模板:
- 进入对应API的集成请求页面,选择「映射模板」,添加
multipart/form-data类型的模板。 - 使用以下模板提取文件内容和文件名(示例为JSON格式):
{ "file_content": "$util.base64Encode($util.parseMultiPartForm($input.body).file[0].content)", "filename": "$util.parseMultiPartForm($input.body).file[0].filename" }
- 进入对应API的集成请求页面,选择「映射模板」,添加
3. Lambda函数处理问题
若Lambda直接将event.body当作文件内容读取,而未解析multipart/form-data或解码Base64,会导致乱码。
Python Lambda示例(处理映射模板传递的数据):
import base64 import io import pandas as pd def lambda_handler(event, context): # 解码Base64格式的文件内容 file_content = base64.b64decode(event['file_content']) # 读取XLSX文件 df = pd.read_excel(io.BytesIO(file_content)) # 转换为JSON并上传S3等后续逻辑... return {"statusCode": 200, "body": "处理完成"}
Node.js Lambda示例(手动解析multipart数据,若未配置映射模板):
使用busboy库解析完整表单数据:
const Busboy = require('busboy'); const XLSX = require('xlsx'); exports.handler = async (event) => { return new Promise((resolve, reject) => { const busboy = new Busboy({ headers: { 'content-type': event.headers['Content-Type'] || event.headers['content-type'] } }); let fileBuffer = Buffer.from(''); busboy.on('file', (_, file) => { file.on('data', (chunk) => { fileBuffer = Buffer.concat([fileBuffer, chunk]); }); file.on('end', () => { // 读取XLSX文件 const workbook = XLSX.read(fileBuffer, { type: 'buffer' }); // 后续JSON转换、上传S3逻辑... resolve({ statusCode: 200, body: '处理完成' }); }); }); busboy.on('error', (err) => reject(err)); busboy.write(Buffer.from(event.body, event.isBase64Encoded ? 'base64' : 'utf8')); busboy.end(); }); };
验证方法
- 查看CloudWatch日志中的
event结构:若event.body包含------WebKitFormBoundary等边界字符串,说明API Gateway未解析表单数据,需检查映射模板或前端请求头。 - 测试前端上传后的请求头:通过浏览器开发者工具确认
Content-Type包含boundary=xxx参数。
内容的提问来源于stack exchange,提问作者Pablo Costa
相关产品推荐
相关产品推荐

