部署AWS Lambda后Node.js+Angular生成的Excel下载后损坏
问题:AWS Lambda部署后Excel文件下载损坏,本地运行正常
使用Node.js结合exceljs库生成Excel文件,通过Angular前端发起请求下载。本地环境下代码运行正常,但部署至AWS Lambda后,下载的Excel文件出现损坏情况,怀疑是API Gateway配置问题,求解决方案。
Node.js 后端代码(原本地版本)
let [row] = await conn.execute( "Query", [] ); let abc = Object.keys(row[0]); var workbook = new excel.Workbook(); var worksheet = workbook.addWorksheet('Sheet1'); let clm = []; abc.forEach(element => { clm.push({ header: element, key: element }); }); worksheet.columns = clm; worksheet.addRows(row); var tempFilePath = tempfile('.xlsx'); workbook.xlsx.writeFile(tempFilePath).then(function () { res.setHeader('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'); res.setHeader("Content-Disposition", "attachment; filename=temp.xlsx"); res.sendFile(tempFilePath, function (err) { // console.log('---------- error downloading file: ' + err); }); });
Angular 前端代码
reports(params: any): Observable<any> { return this.http.post(environment.apiUrl + '/reports', JSON.stringify(params), { responseType: 'arraybuffer' }) .pipe(map((result) => { return result; }), catchError((err) => { throw err; }) ); } this.apicallService .reports(json) .subscribe( (result) => { var blob = new Blob([result], { type : "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"}); var link = document.createElement('a'); link.href = URL.createObjectURL(blob); link.download = filename; link.click(); }, (err) => { this.notifyService.showError(err.message, 'Error'); } );
解决方案
1. 调整Lambda后端代码,适配API Gateway代理集成
本地Express环境的res.sendFile方法在Lambda中不适用,原因是Lambda采用无服务器架构,临时文件存储不可靠,且API Gateway对响应格式有特定要求。修改代码如下:
exports.handler = async (event, context) => { // 数据库查询逻辑保持不变 let [row] = await conn.execute("Query", []); let abc = Object.keys(row[0]); var workbook = new excel.Workbook(); var worksheet = workbook.addWorksheet('Sheet1'); let clm = []; abc.forEach(element => { clm.push({ header: element, key: element }); }); worksheet.columns = clm; worksheet.addRows(row); // 直接生成文件Buffer,避免写入临时文件 const fileBuffer = await workbook.xlsx.writeBuffer(); // 返回符合API Gateway代理集成要求的响应格式 return { statusCode: 200, headers: { 'Content-Type': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'Content-Disposition': 'attachment; filename=temp.xlsx', // 跨域场景需要添加CORS头,根据实际情况调整 'Access-Control-Allow-Origin': '*' }, body: fileBuffer.toString('base64'), isBase64Encoded: true }; };
关键修改点:
- 使用
writeBuffer()直接生成文件二进制Buffer,无需临时文件 - 响应格式必须包含
isBase64Encoded: true,并将Buffer转为base64字符串作为body - 正确设置响应头,包括Content-Type和Content-Disposition
2. 配置API Gateway支持二进制媒体类型
API Gateway默认会把非文本响应转成base64,但需要明确指定允许的二进制类型,否则可能导致数据篡改:
- 登录AWS控制台,进入API Gateway服务
- 选择你的目标API,点击左侧菜单的Settings
- 在Binary Media Types区域,添加
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet - 点击Save Changes,然后重新部署API(Deploy API -> 选择部署阶段 -> Deploy)
3. 优化Angular请求(可选)
原Angular代码中JSON.stringify(params)可改为直接传递对象,并显式设置Content-Type头,避免潜在的格式问题:
reports(params: any): Observable<any> { return this.http.post(environment.apiUrl + '/reports', params, { responseType: 'arraybuffer', headers: new HttpHeaders({ 'Content-Type': 'application/json' }) }) .pipe( map(result => result), catchError(err => { throw err; }) ); }
原因说明
本地环境中Express的sendFile会自动处理二进制文件的传输,但Lambda+API Gateway的组合需要遵循特定的响应规范:API Gateway代理集成要求二进制数据以base64编码返回,并标记isBase64Encoded: true,同时必须在API Gateway中配置对应的Binary Media Types,否则二进制数据会被错误处理,导致下载的Excel文件损坏。
内容的提问来源于stack exchange,提问作者user711241
相关产品推荐
相关产品推荐

