简介:
在为用户提供单个软件包中从Amazon S3下载多个文件的能力时,将这些文件进行z缩是一个普遍的要求。但是,在无服务器环境(例如AWS Lambda)中,需要考虑一些存储和内存约束。在本文中,我们将在克服这些限制的同时,使用node.js探索如何有效地将存储在Amazon S3上的zip文件。我们将利用可读和可写的流以及Archiver库,以优化内存使用和存储空间。
先决条件:
在我们深入实施之前,请确保您有以下先决条件:
- 一个具有访问S3服务的AWS帐户
- Node.js和NPM(Node Package Manager)安装在您的计算机上
- JavaScript和AWS概念的基本知识
步骤1:配置AWS和依赖项:
首先,安装必要的依赖项。创建一个新的node.js项目,然后使用NPM安装以下软件包:
@aws-sdk/client-s3
@aws-sdk/lib-storage
@aws-sdk/s3-request-presigner
archiver
配置我们的AWS凭据在文件本身或单独的config.js文件中提供以下配置。
const AWS_S3_BUCKET = "<aws_s3_bucket>"
const AWS_CONFIG = {
credentials: {
accessKeyId: "<aws_access_key_id>",
secretAccessKey: "<aws_secret_access_key>",
},
region: "<aws_s3_region>",
}
步骤2:来自S3的流数据:
我们首先创建一个称为getReadableStreamFromS3
的函数,该函数将S3密钥作为输入。此功能使用GetObjectCommand
实用程序从@aws-sdk/client-s3
库中获取文件,并将文件作为可读流返回。通过利用流,我们避免将整个文件存储在内存中。
async function getReadableStreamFromS3(s3Key: string) {
const client = new S3Client(AWS_CONFIG);
const command = new GetObjectCommand({
Bucket: AWS_S3_BUCKET,
Key: s3Key,
});
const response = await client.send(command);
return response.Body;
}
步骤3:将拉链数据上传到S3:
接下来,我们创建一个称为getWritableStreamFromS3
的函数,该函数将zipped文件作为输入的目标S3键。此功能利用@aws-sdk/lib-storage
库中的Upload
实用程序。由于Upload
函数不会直接曝光可写的流,因此我们使用Node.js流API的PassThrough
对象采用了“传递流”。该对象充当了可写流的代理,并允许我们有效地将zipped数据上传到S3。
function getWritableStreamFromS3(zipFileS3Key: string) {
let _passthrough = new PassThrough();
const s3 = new S3(AWS_CONFIG);
new Upload({
client: s3,
params: {
Bucket: AWS_S3_BUCKET,
Key: zipFileS3Key,
Body: _passthrough,
},
}).done();
return _passthrough;
}
步骤4:生成和流zip文件到S3:
在此步骤中,我们创建了一个称为generateAndStreamZipfileToS3
的函数,该函数列出了S3键(s3KeyList
)和上传zip文件的目标键(zipFileS3Key
)。在此功能中,我们使用archiver
库来创建Zip Archive。我们通过s3KeyList
迭代,使用getReadableStreamFromS3
将每个文件作为可读的流获取,然后将其附加到zip档案中。然后,我们使用getWritableStreamFromS3
获得了可写的流,然后将拉链档案置于它。最后,我们致电zip.finalize()
启动拉链过程。
async function generateAndStreamZipfileToS3(
s3KeyList: [string],
zipFileS3Key: string
) {
try {
let zip = archiver("zip");
for (const s3Key of s3KeyList) {
const s3ReadableStream = await getReadableStreamFromS3(s3Key);
zip.append(<Readable>s3ReadableStream, { name: s3Key.split("/").pop()! });
}
const s3WritableStream = getWritableStreamFromS3(zipFileS3Key);
zip.pipe(s3WritableStream);
zip.finalize();
} catch (error: any) {
logger.error(`Error in generateAndStreamZipfileToS3 ::: ${error.message}`);
}
}
步骤5:使用预先签名的URL提供Zipped S3文件:
为了提供对Zipped文件的安全访问,我们可以生成有效性有限的预先签名URL。在此可选步骤中,我们创建了一个称为generatePresignedURLforZip
的函数,该函数将zipFileS3Key
作为输入。使用@aws-sdk/s3-request-presigner
库中的GetObjectCommand
实用程序,我们生成了一个预先的URL,该URL在24小时后到期。该URL可以与用户共享,从而使他们可以在指定的时间范围内下载zipped文件。
export async function generatePresignedURLforZip(zipFileS3Key: string) {
logger.info("Generating Presigned URL for the zip file.");
const client = new S3Client(AWS_CONFIG);
const command = new GetObjectCommand({
Bucket: AWS_S3_BUCKET,
Key: zipFileS3Key,
});
const signedUrl = await getSignedUrl(client, command, {
expiresIn: 24 * 3600,
});
return signedUrl;
}
结论:
通过利用可读和可写的流的功能与Archiver库结合使用,我们可以在无服务器环境中有效地将存储在Amazon S3上的ZIP文件。这种方法最大程度地减少了内存使用和存储约束,从而使我们能够处理大型文件,而不会压倒我们的资源。此外,通过使用预先签名的URL,我们可以在有限的持续时间内安全地与用户共享Zipped文件。下次您需要为用户提供一种从S3下载多个文件的方便方法时,请考虑使用node.js。
记住要处理错误,并将适当的错误处理在您的实际实现中。愉快的编码!
参考:
- AWS SDK用于JavaScript文档:https://docs.aws.amazon.com/AWSJavaScriptSDK/
- node.js流文档:https://nodejs.org/api/stream.html
- 档案馆文档:https://archiverjs.com/