在本篇文章中,我们将学习如何设计一个架构,通过该架构我们可以将文件上传到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的角色。)
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腾讯技术创作特训营第五期有奖征文,快来和我瓜分大奖!