构建AWS Lambda触发器:文件上传至S3后自动执行操作的完整指南"

2024-02-08 22:50:02 浏览数 (1)

在本篇文章中,我们将学习如何设计一个架构,通过该架构我们可以将文件上传到AWS S3,并在文件成功上传后触发一个Lambda函数。

该Lambda函数将下载文件并对其进行一些操作。一些可能的选项包括:

  • 生成完整大小图像的缩略图版本
  • 从Excel文件中读取数据
  • 等等

初始化项目

我们将使用AWS Sam进行此项目。我们将使用此项目的typescript设置的样板。

步骤1:

首先,我们需要一些实用函数来从S3下载文件。这些只是纯JavaScript函数,接受一些参数,如存储桶、文件键等,并下载文件。

我们还有一个实用函数用于上传文件。

代码语言:javascript复制
import aws from 'aws-sdk';
import fs from 'fs';

const s3 = new aws.S3();

export class S3Utils {
    static downloadFileFromS3 = function (bucket: string, fileKey: string, filePath: string) {
        console.log('downloading', bucket, fileKey, filePath);
        return new Promise((resolve, reject) => {
            const file = fs.createWriteStream(filePath),
                stream = s3
                    .getObject({
                        Bucket: bucket,
                        Key: fileKey
                    })
                    .createReadStream();
            stream.on('error', reject);
            file.on('error', reject);
            file.on('finish', () => {
                console.log('downloaded', bucket, fileKey);
                resolve(filePath);
            });
            stream.pipe(file);
        });
    };

    static uploadFileToS3 = function (
        bucket: string,
        fileKey: string,
        filePath: string,
        contentType: string
    ) {
        console.log('uploading', bucket, fileKey, filePath);
        return s3
            .upload({
                Bucket: bucket,
                Key: fileKey,
                Body: fs.createReadStream(filePath),
                ACL: 'private',
                ContentType: contentType
            })
            .promise();
    };

    static cleanDownloadedFile = async (filePath: string) => {
        await fs.unlink(filePath, (err) => {
            console.log('temporary file deleted ');
        });
    };
}

最后,还有一个从本地机器上删除文件的函数。

步骤2:

然后,我们需要在src文件夹下添加实际的Lambda处理程序。

在此Lambda中,事件对象将是S3CreateEvent,因为我们希望在将新文件上传到特定S3存储桶时触发此函数。

注意:此函数用于读取 .xlsx 和 .csv 文件。如果要支持其他文件,你将需要将其添加到supportedFormats数组中。

代码语言:javascript复制
import { S3CreateEvent, Context } from 'aws-lambda';
import path from 'path';
import os from 'os';
import { S3Utils } from '../utils/s3-utils';

const supportedFormats = ['csv', 'xlsx'];

function extractS3Info(event: S3CreateEvent) {
    const eventRecord = event.Records && event.Records[0];
    const bucket = eventRecord.s3.bucket.name;
    const { key } = eventRecord.s3.object;
    return { bucket, key };
}

exports.handler = async (event: S3CreateEvent, context: Context) => {
    try {
        const s3Info = extractS3Info(event);
        const id = context.awsRequestId;
        const extension = path.extname(s3Info.key).toLowerCase();
        const tempFile = path.join(os.tmpdir(), id   extension);
        const extensionWithoutDot = extension.slice(1);

        console.log('converting', s3Info.bucket, ':', s3Info.key, 'using', tempFile);
        if (!supportedFormats.includes(extensionWithoutDot)) {
            throw new Error(`unsupported file type ${extension}`);
        }
        await S3Utils.downloadFileFromS3(s3Info.bucket, s3Info.key, tempFile);
        // 进行你想要的文件操作
        // contentType = `image/${extensionWithoutDot}`;
        // await S3Utils.uploadFileToS3(OUTPUT_BUCKET, s3Info.key, tempFile, contentType);
        await S3Utils.cleanDownloadedFile(tempFile);
    } catch (err) {
        console.log(JSON.stringify(err));
    }
};

步骤3:

最后一部分是更新template.yaml文件。在这里我们添加了三个东西。

  • 一个S3存储桶,我们将在其中上传文件。
  • 当将新文件上传到桶中时,将触发Lambda。请注意在Events属性中指定事件将是s3:ObjectCreated。我们还在这里链接了桶。
  • 一个允许Lambda读取s3桶内容的策略。我们还将策略附加到函数的角色上。(为每个函数创建一个角色。所以LambdaThatWillReactToFileUpload函数将具有一个名为LambdaThatWillReactToFileUploadRole的角色。)
代码语言:yaml复制
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: AWS SAM demo Lambda react to file uploaded to s3

Globals:
    Function:
        Runtime: nodejs14.x
        Timeout: 30

Resources:
    S3BucketToRespond:
        Type: AWS::S3::Bucket
        Properties:
            BucketName: 'Dummy-Bucket'
    
    LambdaThatWillReactToFileUpload:
        Type: AWS::Serverless::Function
        Properties:
            CodeUri: src/s3-file-upload-reaction
            Handler: app.handler
            Events:
                FileUploadedToS3:
                    Type: S3
                    Properties:
                        Bucket: !Ref S3BucketToRespond
                        Events: s3:ObjectCreated:*

    ReadS3BucketPolicy:
        Type: AWS::IAM::Policy
        Properties:
            PolicyName: ReadS3BucketPolicy
            PolicyDocument:
                Version: '2012-10-17'
                Statement:
                    - Effect: Allow
                      Action:
                          - s3:GetObject
                      Resource:
                          - !Sub '${S3BucketToRespond.Arn}/*'
            Roles:
                - !Ref LambdaThatWillReactToFileUploadRole

我们添加了额外的策

略以避免循环依赖问题。至此,你将根据你所在的区域部署代码。

要部署应用程序,你首先配置环境。你可以在此处找到详细信息。

然后运行以下命令进行部署

代码语言:bash复制
sam deploy --guided

测试

要测试它是否起作用,转到AWS S3控制台,上传文件并检查日志。

要从本地机器检查日志

代码语言:bash复制
sam logs -n LambdaThatWillReactToFileUpload --stack-name sam-lambda-trigger-s3-file-upload --tail

然后你将在那里看到日志。

我正在参与2024腾讯技术创作特训营第五期有奖征文,快来和我瓜分大奖!

0 人点赞