Lambda处理程序响应体流返回:Serverless场景S3压缩包下载报错咨询
错误原因
- 你引入的是
fs/promisespromise化的fs模块,这个模块不包含createReadStream方法,该方法只存在于基础fs模块中 - Lambda运行环境的
__dirname目录是只读的,不能往这里写文件,必须写到Lambda提供的临时目录/tmp下 - Lambda的响应对象不能用流的
pipe方法直接写入,需要把zip文件转为Buffer后base64编码返回,同时要设置正确的响应头让浏览器识别为下载文件
修改后可运行代码
// 引入需要的依赖 const fs = require('fs'); const fsp = require('fs/promises'); const AdmZip = require('adm-zip'); const AWS = require('aws-sdk'); const s3 = new AWS.S3(); const BUCKET_NAME = '替换为你的S3桶名'; module.exports.handler = async (event) => { const response = { isBase64Encoded: true, // 二进制文件需要开启base64编码返回 statusCode: 200, headers: { 'Content-Type': 'application/zip', 'Content-Disposition': `attachment; filename="download.zip"` // 自定义下载后的文件名 } }; try { const params = { Bucket: BUCKET_NAME, Key: decodeURIComponent(event.pathParameters.fileKey), }; const data = await s3.getObject(params).promise(); const zip = new AdmZip(data.Body); const entries = zip.getEntries(); let newZip = new AdmZip(); for(let entry of entries){ newZip.addFile(entry.entryName, entry.getCompressedData()); } // 写入Lambda临时目录 const zipPath = `/tmp/${Date.now()}.zip`; newZip.writeZip(zipPath); // 读取文件为Buffer后转base64 const zipBuffer = await fsp.readFile(zipPath); response.body = zipBuffer.toString('base64'); // 可选:删除临时文件避免占用临时空间 await fsp.unlink(zipPath); } catch (error) { console.error(error); response.headers = { 'Content-Type': 'application/json' }; response.isBase64Encoded = false; response.body = JSON.stringify({ message: 'Failed To Get File', errorMessage: error.message }); response.statusCode = 500; } return response; };
可选优化方案(无需操作本地文件)
AdmZip支持直接生成内存Buffer不需要写入磁盘,可以完全去掉文件读写逻辑,代码更简洁,性能也更高,替换zip处理逻辑即可:
const data = await s3.getObject(params).promise(); const zip = new AdmZip(data.Body); const entries = zip.getEntries(); let newZip = new AdmZip(); for(let entry of entries){ newZip.addFile(entry.entryName, entry.getCompressedData()); } // 直接生成内存buffer转base64,无需读写磁盘 response.body = newZip.toBuffer().toString('base64');
内容的提问来源于stack exchange,提问作者lmac
相关产品推荐
相关产品推荐

