为您的函数代码和依赖项创建一个名为
lambda-s3
的目录并导航到此目录。
mkdir lambda-s3
cd lambda-s3
使用
npm
创建新的 Node.js 项目。要在交互式体验中接受提供的默认选项,请按
Enter
。
npm init
将以下函数代码保存在名为
index.mjs
的文件中。请务必将
us-east-1
替换您创建源存储桶和目标存储桶时所在的 AWS 区域。
// dependencies
import { S3Client, GetObjectCommand, PutObjectCommand } from '@aws-sdk/client-s3';
import { Readable } from 'stream';
import sharp from 'sharp';
import util from 'util';
// create S3 client
const s3 = new S3Client({region: 'us-east-1'
});
// define the handler function
export const handler = async (event, context) => {
// Read options from the event parameter and get the source bucket
console.log("Reading options from event:\n", util.inspect(event, {depth: 5}));
const srcBucket = event.Records[0].s3.bucket.name;
// Object key may have spaces or unicode non-ASCII characters
const srcKey = decodeURIComponent(event.Records[0].s3.object.key.replace(/\+/g, " "));
const dstBucket = srcBucket + "-resized";
const dstKey = "resized-" + srcKey;
// Infer the image type from the file suffix
const typeMatch = srcKey.match(/\.([^.]*)$/);
if (!typeMatch) {
console.log("Could not determine the image type.");
return;
// Check that the image type is supported
const imageType = typeMatch[1].toLowerCase();
if (imageType != "jpg" && imageType != "png") {
console.log(`Unsupported image type: ${imageType}`);
return;
// Get the image from the source bucket. GetObjectCommand returns a stream.
try {
const params = {
Bucket: srcBucket,
Key: srcKey
var response = await s3.send(new GetObjectCommand(params));
var stream = response.Body;
// Convert stream to buffer to pass to sharp resize function.
if (stream instanceof Readable) {
var content_buffer = Buffer.concat(await stream.toArray());
} else {
throw new Error('Unknown object stream type');
} catch (error) {
console.log(error);
return;
// set thumbnail width. Resize will set the height automatically to maintain aspect ratio.
const width = 200;
// Use the sharp module to resize the image and save in a buffer.
try {
var output_buffer = await sharp(content_buffer).resize(width).toBuffer();
} catch (error) {
console.log(error);
return;
// Upload the thumbnail image to the destination bucket
try {
const destparams = {
Bucket: dstBucket,
Key: dstKey,
Body: output_buffer,
ContentType: "image"
const putResult = await s3.send(new PutObjectCommand(destparams));
} catch (error) {
console.log(error);
return;
console.log('Successfully resized ' + srcBucket + '/' + srcKey +
' and uploaded to ' + dstBucket + '/' + dstKey);
在 lambda-s3
目录中,使用 npm 安装 sharp 库。请注意,最新版本的 sharp(0.33)与 Lambda 不兼容。安装版本 0.32.6 以完成本教程。
npm install [email protected]
npm install
命令会为模块创建 node_modules
目录。完成此步骤后,目录结构应如下所示:
lambda-s3
|- index.mjs
|- node_modules
| |- base64js
| |- bl
| |- buffer
|- package-lock.json
|- package.json
创建一个包含函数代码和依赖项的部署包。在 MacOS 或 Linux 中,运行以下命令。
zip -r function.zip .
在 Windows 中,使用您首选的 ZIP 实用工具来创建 .zip 文件。确保您的 index.mjs
、package.json
、和 package-lock.json
文件以及您的 node_modules
目录都在.zip 文件的根目录中。
Python
创建部署包(Python)
-
将代码示例保存为名为 lambda_function.py
的文件。
import boto3
import os
import sys
import uuid
from urllib.parse import unquote_plus
from PIL import Image
import PIL.Image
s3_client = boto3.client('s3')
def resize_image(image_path, resized_path):
with Image.open(image_path) as image:
image.thumbnail(tuple(x / 2 for x in image.size))
image.save(resized_path)
def lambda_handler(event, context):
for record in event['Records']:
bucket = record['s3']['bucket']['name']
key = unquote_plus(record['s3']['object']['key'])
tmpkey = key.replace('/', '')
download_path = '/tmp/{}{}'.format(uuid.uuid4(), tmpkey)
upload_path = '/tmp/resized-{}'.format(tmpkey)
s3_client.download_file(bucket, key, download_path)
resize_image(download_path, upload_path)
s3_client.upload_file(upload_path, '{}-resized'.format(bucket), 'resized-{}'.format(key))
在创建 lambda_function.py
文件的同一目录中,创建一个名为 package
的新目录并安装 Pillow(PIL)库和 AWS SDK for Python (Boto3)。虽然 Lambda Python 运行时系统包含 Boto3 SDK 的一个版本,但建议您将所有函数的依赖项添加到部署包中,即使这些依赖项已经包含在了运行时系统中。有关更多信息,请参阅 Python 中的运行时系统依赖项。
mkdir package
pip install \
--platform manylinux2014_x86_64 \
--target=package \
--implementation cp \
--python-version 3.12 \
--only-binary=:all: --upgrade \
pillow boto3
Pillow 库包含 C/C++ 代码。通过使用 --platform manylinux_2014_x86_64
和 --only-binary=:all:
选项,pip 将下载并安装包含与 Amazon Linux 2 操作系统兼容的预编译二进制文件的 Pillow 版本。这可以确保无论本地构建计算机的操作系统和架构如何,部署包都能在 Lambda 执行环境中正常发挥作用。
创建包含应用程序代码和 Pillow 以及 Boto3 库的 zip 文件。在 Linux 或 MacOS 中,从命令行界面运行以下命令。
cd package
zip -r ../lambda_function.zip .
cd ..
zip lambda_function.zip lambda_function.py
在 Windows 中,使用您首选的压缩工具来创建 lambda_function.zip
文件。确保您的 lambda_function.py
文件和包含依赖项的文件夹都位于.zip 文件的根目录下。
您也可以使用 Python 虚拟环境创建部署包。请参阅 将 .zip 文件归档用于 Python Lambda 函数。
- AWS Management Console
-
创建函数(控制台)
要使用控制台创建 Lambda 函数,首先要创建包含一些“Hello world”代码的基本函数。然后,通过上传在上一步中创建的 .zip 或 JAR 文件,将此代码替换为自己的函数代码。
-
打开 Lamba 控制台的函数页面。
确保您在创建 Amazon S3 存储桶所在的同一 AWS 区域 内操作。您可以使用屏幕顶部的下拉列表更改区域。
对于 Function name(函数名称),请输入 CreateThumbnail
。
对于运行时,根据您为函数选择的语言,选择 Node.js 20.x 或 Python 3.12。
对于架构,选择 x86_64。
在更改默认执行角色选项卡中,执行以下操作:
展开选项卡,然后选择使用现有角色。
选择您之前创建的 LambdaS3Role
。
选择 Create function (创建函数)。
上传函数代码(控制台)
-
在代码源窗格中,选择上传自。
选择 .zip 文件。
选择上传。
在文件选择器中,选择 .zip 文件,然后选择打开。
选择保存。
- AWS CLI
-
创建函数(AWS CLI)
-
运行您所选语言的 CLI 命令。对于 role
参数,确保将 123456789012
替换为自己的 AWS 账户 ID。对于 region
参数,将 us-east-1
替换为在其中创建 Amazon S3 存储桶的区域。
对于 Node.js,从包含 function.zip
文件的目录中运行以下命令。
aws lambda create-function --function-name CreateThumbnail \
--zip-file fileb://function.zip --handler index.handler --runtime nodejs20.x \
--timeout 10 --memory-size 1024 \
--role arn:aws:iam::123456789012
:role/LambdaS3Role --region us-east-1
对于 Python,从包含 lambda_function.zip
文件的目录中运行以下命令。
aws lambda create-function --function-name CreateThumbnail \
--zip-file fileb://lambda_function.zip --handler lambda_function.lambda_handler \
--runtime python3.12 --timeout 10 --memory-size 1024 \
--role arn:aws:iam::123456789012
:role/LambdaS3Role --region us-east-1
要在将图像上传到源存储桶时运行 Lambda 函数,您需要为函数配置触发器。您可以使用控制台或 AWS CLI 配置 Amazon S3 触发器。
此程序将 Amazon S3 存储桶配置为每次在此存储桶中创建对象时调用您的函数。请确保仅在源存储桶上配置。如果您的 Lambda 函数在调用此函数的同一个存储桶中创建对象,则可以在循环中持续调用您的函数。这可能会导致您的 AWS 账户 产生额外费用。
- AWS Management Console
-
配置 Amazon S3 触发器(控制台)
-
打开 Lambda 控制台的函数页面,然后选择函数 (CreateThumbnail
)。
选择添加触发器。
选择 S3。
在存储桶下,选择自己的源存储桶。
在事件类型下,选择所有对象创建事件。
在递归调用下,选中复选框以确认知晓不建议使用相同的 Amazon S3 存储桶用于输入和输出。您可以阅读 Serverless Land 中的 Recursive patterns that cause run-away Lambda functions,进一步了解 Lambda 中的递归调用模式。
选择添加。
在您使用 Lambda 控制台创建触发器时,Lambda 会自动创建基于资源的策略,授予您选择的服务调用函数的权限。
- AWS CLI
-
配置 Amazon S3 触发器(AWS CLI)
-
要让 Amazon S3 源存储桶在添加图像文件时调用函数,您首先需要使用基于资源的策略为函数配置权限。基于资源的策略声明授予其他 AWS 服务 调用您函数的权限。要授予 Amazon S3 调用函数的权限,请运行以下 CLI 命令。请务必将 source-account
参数替换为您的 AWS 账户 ID 并使用自己的源存储桶名称。
aws lambda add-permission --function-name CreateThumbnail \
--principal s3.amazonaws.com --statement-id s3invoke --action "lambda:InvokeFunction" \
--source-arn arn:aws:s3:::amzn-s3-demo-source-bucket
\
--source-account 123456789012
您使用此命令定义的策略允许 Amazon S3 仅在源存储桶上执行操作时调用函数。
虽然 Amazon S3 存储桶名称具有全局唯一性,但在使用基于资源的策略时,最佳做法是指定存储桶必须属于您的账户。这是因为,如果删除一个存储桶,则另一个 AWS 账户 账户可能会创建具有相同 Amazon 资源名称(ARN)的存储桶。
将下列 JSON 保存在名为 notification.json
的文件中。在应用到您的源存储桶时,此 JSON 会将存储桶配置为在每次添加新对象时向 Lambda 函数发送通知。将 Lambda 函数 ARN 中的 AWS 账户 号码和 AWS 区域 替换为您自己的账号和区域。
"LambdaFunctionConfigurations": [
"Id": "CreateThumbnailEventConfiguration",
"LambdaFunctionArn": "arn:aws:lambda:us-east-1:123456789012
:function:CreateThumbnail",
"Events": [ "s3:ObjectCreated:Put" ]
运行以下 CLI 命令,将您创建的 JSON 文件中的通知设置应用到源存储桶。将 amzn-s3-demo-source-bucket
替换为源存储桶的名称。
aws s3api put-bucket-notification-configuration --bucket amzn-s3-demo-source-bucket
\
--notification-configuration file://notification.json
要了解有关 put-bucket-notification-configuration
命令和 notification-configuration
选项的更多信息,请参阅 AWS CLI 命令参考中的 put-bucket-notification-configuration。
在通过向 Amazon S3 源存储桶添加图像文件来测试整个设置之前,您可以通过使用虚拟事件调用 Lambda 函数来测试此函数是否正常运行。Lambda 中的事件是 JSON 格式的文档,其中包含要处理的函数数据。Amazon S3 调用您的函数时,发送到函数的事件包含存储桶名称、存储桶 ARN 和对象键等信息。
- AWS Management Console
-
使用虚拟事件测试 Lambda 函数(控制台)
-
打开 Lambda 控制台的函数页面,然后选择函数 (CreateThumbnail
)。
选择测试选项卡。
要创建测试事件,在测试事件窗格中,执行以下操作:
在测试事件操作下,选择创建新事件。
对于事件名称,输入 myTestEvent
。
在模板中,选择 S3 Put。
将以下参数的值替换为您自己的值。
对于 awsRegion
,将 us-east-1
替换为在其中创建 Amazon S3 存储桶的 AWS 区域。
对于 name
,将 amzn-s3-demo-bucket
替换为您自己的 Amazon S3 源存储桶的名称。
对于 key
,将 test%2Fkey
替换为您在步骤 将测试图片上传到源存储桶 中上传到源存储桶的测试对象的文件名。
"Records": [
"eventVersion": "2.0",
"eventSource": "aws:s3",
"awsRegion": "us-east-1"
,
"eventTime": "1970-01-01T00:00:00.000Z",
"eventName": "ObjectCreated:Put",
"userIdentity": {
"principalId": "EXAMPLE"
"requestParameters": {
"sourceIPAddress": "127.0.0.1"
"responseElements": {
"x-amz-request-id": "EXAMPLE123456789",
"x-amz-id-2": "EXAMPLE123/5678abcdefghijklambdaisawesome/mnopqrstuvwxyzABCDEFGH"
"s3": {
"s3SchemaVersion": "1.0",
"configurationId": "testConfigRule",
"bucket": {
"name": "amzn-s3-demo-bucket"
,
"ownerIdentity": {
"principalId": "EXAMPLE"
"arn": "arn:aws:s3:::amzn-s3-demo-bucket"
"object": {
"key": "test%2Fkey"
,
"size": 1024,
"eTag": "0123456789abcdef0123456789abcdef",
"sequencer": "0A1B2C3D4E5F678901"
选择保存。
在测试事件窗格中,选择测试。
要检查您的函数是否已创建图像的调整大小版本并将其存储在目标 Amazon S3 存储桶中,请执行以下操作:
打开 Amazon S3 控制台的存储桶页面。
选择目标存储桶并确认调整大小的文件已在对象窗格中列出。
- AWS CLI
-
使用虚拟事件测试 Lambda 函数(AWS CLI)
-
将下列 JSON 保存在名为 dummyS3Event.json
的文件中。将以下参数的值替换为您自己的值:
对于 awsRegion
,将 us-east-1
替换为在其中创建 Amazon S3 存储桶的 AWS 区域。
对于 name
,将 amzn-s3-demo-bucket
替换为您自己的 Amazon S3 源存储桶的名称。
对于 key
,将 test%2Fkey
替换为您在步骤 将测试图片上传到源存储桶 中上传到源存储桶的测试对象的文件名。
"Records": [
"eventVersion": "2.0",
"eventSource": "aws:s3",
"awsRegion": "us-east-1"
,
"eventTime": "1970-01-01T00:00:00.000Z",
"eventName": "ObjectCreated:Put",
"userIdentity": {
"principalId": "EXAMPLE"
"requestParameters": {
"sourceIPAddress": "127.0.0.1"
"responseElements": {
"x-amz-request-id": "EXAMPLE123456789",
"x-amz-id-2": "EXAMPLE123/5678abcdefghijklambdaisawesome/mnopqrstuvwxyzABCDEFGH"
"s3": {
"s3SchemaVersion": "1.0",
"configurationId": "testConfigRule",
"bucket": {
"name": "amzn-s3-demo-bucket"
,
"ownerIdentity": {
"principalId": "EXAMPLE"
"arn": "arn:aws:s3:::amzn-s3-demo-bucket"
"object": {
"key": "test%2Fkey"
,
"size": 1024,
"eTag": "0123456789abcdef0123456789abcdef",
"sequencer": "0A1B2C3D4E5F678901"
在保存 dummyS3Event.json
文件的目录中,运行以下 CLI 命令来调用函数。此命令通过指定 RequestResponse
作为调用类型参数的值来同步调用 Lambda 函数。要了解有关同步和异步调用的更多信息,请参阅调用 Lambda 函数。
aws lambda invoke --function-name CreateThumbnail \
--invocation-type RequestResponse --cli-binary-format raw-in-base64-out \
--payload file://dummyS3Event.json outputfile.txt
如果您使用的是 AWS CLI 版本 2,则 cli-binary-format 选项必填。要将其设为默认设置,请运行 aws configure set cli-binary-format raw-in-base64-out
。有关更多信息,请参阅AWS CLI 支持的全局命令行选项。
验证您的函数是否已创建图像的缩略图版本并已保存到目标 Amazon S3 存储桶中。运行以下 CLI 命令,将 amzn-s3-demo-source-bucket-resized
替换为自己的目标存储桶的名称。
aws s3api list-objects-v2 --bucket amzn-s3-demo-source-bucket-resized
您应该可以看到类似于如下所示的输出内容。Key
参数显示调整大小后的图像文件的文件名。
"Contents": [
"Key": "resized-HappyFace.jpg",
"LastModified": "2023-06-06T21:40:07+00:00",
"ETag": "\"d8ca652ffe83ba6b721ffc20d9d7174a\"",
"Size": 2633,
"StorageClass": "STANDARD"
此时,您已确认 Lambda 函数运行正常,您可以通过向 Amazon S3 源存储桶添加图像文件来测试完整设置。将图像添加到源存储桶时,应自动调用 Lambda 函数。函数会创建文件已调整大小的版本并将其存储在目标存储桶中。
- AWS Management Console
-
使用 Amazon S3 触发器测试 Lambda 函数(控制台)
-
要将图像上传到 Amazon S3 存储桶,请执行以下操作:
打开 Amazon S3 控制台的存储桶页面,然后选择您的源存储桶。
选择上传。
选择添加文件,然后使用文件选择器选择要上传的图像文件。您的图像对象可以是任何.jpg 或.png 文件。
选择打开,然后选择上传。
执行以下操作,验证 Lambda 是否已将调整大小后的图像文件保存在目标存储桶中:
导航回 Amazon S3 控制台的存储桶页面,然后选择您的目标存储桶。
在对象窗格中,您现在应该能看到两个已调整大小的图像文件,其中一个来自 Lambda 函数的每次测试。要下载已调整大小的图像,请选择所需文件,然后选择下载。
- AWS CLI
-
使用 Amazon S3 触发器测试 Lambda 函数(AWS CLI)
-
在包含要上传的图像的目录中,运行以下 CLI 命令。将 --bucket
参数替换为源存储桶的名称。对于--key
和 --body
参数,请使用测试图像的文件名。您的测试图像可以是任何.jpg 或.png 文件。
aws s3api put-object --bucket amzn-s3-demo-source-bucket
--key SmileyFace.jpg
--body ./SmileyFace.jpg
验证您的函数是否已创建图像的缩略图版本并已保存到目标 Amazon S3 存储桶中。运行以下 CLI 命令,将 amzn-s3-demo-source-bucket-resized
替换为自己的目标存储桶的名称。
aws s3api list-objects-v2 --bucket amzn-s3-demo-source-bucket-resized
如果函数成功运行,您将看到类似于以下内容的输出。您的目标存储桶现在应该包含两个已调整大小的文件。
"Contents": [
"Key": "resized-HappyFace.jpg",
"LastModified": "2023-06-07T00:15:50+00:00",
"ETag": "\"7781a43e765a8301713f533d70968a1e\"",
"Size": 2763,
"StorageClass": "STANDARD"
"Key": "resized-SmileyFace.jpg",
"LastModified": "2023-06-07T00:13:18+00:00",
"ETag": "\"ca536e5a1b9e32b22cd549e18792cdbc\"",
"Size": 1245,
"StorageClass": "STANDARD"