Lambda 函数处理程序是函数代码中处理事件的方法。当调用函数时,Lambda 运行处理程序方法。您的函数会一直运行,直到处理程序返回响应、退出或超时。
本页介绍了如何使用 Node.js Lambda 函数处理程序,包括项目设置选项、命名约定和最佳实践。本页还包括 Node.js Lambda 函数的示例,在示例中该函数接收订单信息,生成文本文件收据,然后将此文件放入 Amazon Simple Storage Service(Amazon S3)存储桶中。有关如何在编写函数后部署函数的信息,请参阅使用 .zip 文件归档部署 Node.js Lambda 函数或使用容器映像部署 Node.js Lambda 函数。
主题
设置 Node.js 处理程序项目
有多种方法可初始化 Node.js Lambda 项目。例如,您可以使用 npm
创建标准 Node.js 项目、创建 AWS SAM 应用程序或创建 AWS CDK 应用程序。
使用 npm
创建项目:
npm init
此命令将初始化项目,并生成管理项目元数据和依赖项的 package.json
文件。
您的函数代码位于 .js
或 .mjs
JavaScript 文件中。在以下示例中,我们将此文件命名为 index.mjs
,因为其使用了 ES 模块处理程序。Lambda 同时支持 ES 模块和 CommonJS 处理程序。有关更多信息,请参阅 将函数处理程序指定为 ES 模块。
典型的 Node.js Lambda 函数项目遵循以下一般结构:
/project-root ├── index.mjs — Contains main handler ├── package.json — Project metadata and dependencies ├── package-lock.json — Dependency lock file └── node_modules/ — Installed dependencies
示例 Node.js Lambda 函数代码
以下示例 Lambda 函数代码接收有关订单的信息,生成文本文件接收,并将此文件放入 Amazon S3 存储桶中。
注意
此示例使用了 ES 模块处理程序。Lambda 同时支持 ES 模块和 CommonJS 处理程序。有关更多信息,请参阅 将函数处理程序指定为 ES 模块。
例 index.mjs Lambda 函数
import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';
// Initialize the S3 client outside the handler for reuse
const s3Client = new S3Client();
/**
* Lambda handler for processing orders and storing receipts in S3.
* @param {Object} event - Input event containing order details
* @param {string} event.order_id - The unique identifier for the order
* @param {number} event.amount - The order amount
* @param {string} event.item - The item purchased
* @returns {Promise<string>} Success message
*/
export const handler = async(event) => {
try {
// Access environment variables
const bucketName = process.env.RECEIPT_BUCKET;
if (!bucketName) {
throw new Error('RECEIPT_BUCKET environment variable is not set');
}
// Create the receipt content and key destination
const receiptContent = `OrderID: ${event.order_id}\nAmount: $${event.amount.toFixed(2)}\nItem: ${event.item}`;
const key = `receipts/${event.order_id}.txt`;
// Upload the receipt to S3
await uploadReceiptToS3(bucketName, key, receiptContent);
console.log(`Successfully processed order ${event.order_id} and stored receipt in S3 bucket ${bucketName}`);
return 'Success';
} catch (error) {
console.error(`Failed to process order: ${error.message}`);
throw error;
}
};
/**
* Helper function to upload receipt to S3
* @param {string} bucketName - The S3 bucket name
* @param {string} key - The S3 object key
* @param {string} receiptContent - The content to upload
* @returns {Promise<void>}
*/
async function uploadReceiptToS3(bucketName, key, receiptContent) {
try {
const command = new PutObjectCommand({
Bucket: bucketName,
Key: key,
Body: receiptContent
});
await s3Client.send(command);
} catch (error) {
throw new Error(`Failed to upload receipt to S3: ${error.message}`);
}
}
此 index.mjs
文件包含以下代码部分:
-
import
数据块:使用此数据块来包含 Lambda 函数所需的库,例如 AWS SDK 客户端。 -
const s3Client
声明:用于在处理程序函数之外初始化 Amazon S3 客户端。这会导致 Lambda 在初始化阶段运行此代码,并保留客户端以供多次调用时重复使用。 -
JSDoc 注释块:使用 JSDoc 注释
为处理程序定义输入和输出类型。 -
export const handler
:这是 Lambda 调用的主要处理程序函数。部署函数时,请为处理程序属性指定index.handler
。Handler
属性的值是文件的名称和导出的处理程序方法的名称(由点分隔)。 -
uploadReceiptToS3
函数:这是主要处理程序函数引用的帮助函数。
要使此函数正常运行,其执行角色必须允许 s3:PutObject
操作。此外,请确保您定义了 RECEIPT_BUCKET
环境变量。成功调用后,Amazon S3 存储桶应包含接收文件。
处理程序命名约定
配置函数时,处理程序设置的值是文件的名称和导出的处理程序方法的名称(由点分隔)。控制台中创建的函数的默认值为 index.handler
,这也是本指南所用示例的值。这表示从 index.js
或 index.mjs
文件中导出的 handler
方法。
如果您在控制台中使用不同的文件名或函数处理程序名称创建函数,则必须编辑默认处理程序名称。
更改函数处理程序名称(控制台)
-
打开 Lambda 控制台的函数
页面,然后选择一个函数。 -
选择节点选项卡。
-
向下滚动到运行时设置窗格并选择编辑。
-
在处理程序中,输入函数处理程序的新名称。
-
选择保存。
定义和访问输入事件对象
JSON 是 Lambda 函数最常用且最标准的输入格式。在此示例中,该函数需要类似于下方的输入:
{
"order_id": "12345",
"amount": 199.99,
"item": "Wireless Headphones"
}
在使用 Node.js Lambda 函数时,您可以使用 JSDoc 注释定义输入事件的预期形状。在此示例中,我们在处理程序的 JSDoc 注释中定义了输入结构:
/**
* Lambda handler for processing orders and storing receipts in S3.
* @param {Object} event - Input event containing order details
* @param {string} event.order_id - The unique identifier for the order
* @param {number} event.amount - The order amount
* @param {string} event.item - The item purchased
* @returns {Promise<string>} Success message
*/
在 JSDoc 注释中定义了这些类型后,您可以直接在代码中访问事件对象的字段。例如,event.order_id
从原始输入中检索 order_id
的值。
Node.js 函数的有效处理程序模式
建议您使用 async/await 来声明函数处理程序,而不是使用回调。Async/await 是一种简洁、易读的异步代码编写方式,无需使用嵌套回调或链式承诺。使用 Async/await 时,您编写的代码看起来与同步代码类似,同时仍然是异步和非阻止式的。
使用 async/await(推荐)
async
关键字会将函数标记为异步,await
关键字会暂停函数的执行,直到 Promise
完成解析为止。处理程序接受以下参数:
-
event
:包含传递给您函数的输入数据。 -
context
:包含有关调用、函数和执行环境的信息。有关更多信息,请参阅 使用 Lambda 上下文对象检索 Node.js 函数信息。
以下为 async/await 模式的有效签名:
export const handler = async
(event)
=> { };export const handler = async
(event, context)
=> { };
注意
使用本地集成式开发环境(IDE)或文本编辑器来编写 TypeScript 函数代码。您无法在 Lambda 控制台上创建 TypeScript 代码。
使用回调
回调处理程序可以使用事件、上下文和回调参数。以下为有效签名:
export const handler =
(event, callback)
=> { };export const handler =
(event, context, callback)
=> { };
回调函数需要一个 Error
和一个响应,该响应必须是 JSON 可序列化的。函数会一直执行,直到事件循环
例 – 包含 callback 的 HTTP 请求
以下示例函数检查 URL 并向调用方返回状态代码。
import https from "https";
let url = "https://aws.amazon.com/";
export const handler = (event, context, callback) => {
https.get(url, (res) => {
callback(null, res.statusCode);
}).on("error", (e) => {
callback(Error(e));
});
};
在处理程序中使用适用于 JavaScript v3 的 SDK
通常,您将使用 Lambda 函数与其他 AWS 资源进行交互或对其进行更新。与此类资源最简单的交互方法是使用 适用于 JavaScript 的 AWS SDK。所有支持的 Lambda Node.js 运行时都包含适用于 JavaScript 版本 3 的 SDK。但是,强烈建议您在部署包中包含所需的 AWS SDK 客户端。这样可以最大限度地提高未来 Lambda 运行时更新期间的向后兼容性。只有在无法包含其他程序包时(例如,在 AWS CloudFormation 模板中使用 Lambda 控制台代码编辑器或内联代码时),才依赖运行时提供的 SDK。
要向函数添加 SDK 依赖项,请使用适用于所需特定 SDK 客户端的 npm install
命令。在示例代码中,我们使用了 Amazon S3 客户端。在包含 package.json
文件的目录中,运行以下命令添加此依赖项:
npm install @aws-sdk/client-s3
在函数代码中,导入所需的客户端和命令,如示例函数所示:
import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';
然后,初始化 Amazon S3 客户端:
const s3Client = new S3Client();
在此示例中,我们在主处理程序函数之外初始化了 Amazon S3 客户端,以免每次调用函数时都必须对其进行初始化。初始化 SDK 客户端后,就可以使用它为 AWS 服务发出 API 调用。示例代码按如下方式调用 Amazon S3 PutObject API:
const command = new PutObjectCommand({
Bucket: bucketName,
Key: key,
Body: receiptContent
});
评估环境变量
在处理程序代码中,您可以使用 process.env
引用任意环境变量。在此示例中,我们使用以下代码行来引用已定义的 RECEIPT_BUCKET
环境变量:
// Access environment variables
const bucketName = process.env.RECEIPT_BUCKET;
if (!bucketName) {
throw new Error('RECEIPT_BUCKET environment variable is not set');
}
使用全局状态
在首次调用您的函数之前,Lambda 会在初始化阶段运行您的静态代码。初始化期间创建的资源在两次调用之间保留在内存中,因此您可以避免每次调用函数时都必须创建这些资源的情况。
在示例代码中,S3 客户端初始化代码位于主处理程序之外。运行时会在函数处理第一个事件之前初始化客户端,之后所有的调用都可以重复使用该客户端。
Node.js Lambda 函数的代码最佳实践
构建 Lambda 函数时请遵循以下准则:
-
从核心逻辑中分离 Lambda 处理程序。这样您可以创建更容易进行单元测试的函数。
-
控制函数部署程序包中的依赖关系。AWS Lambda 执行环境包含许多库。对于 Node.js 和 Python 运行时,其中包括 AWS SDK。Lambda 会定期更新这些库,以支持最新的功能组合和安全更新。这些更新可能会使 Lambda 函数的行为发生细微变化。要完全控制您的函数所用的依赖项,请使用部署程序包来打包所有依赖项。
-
将依赖关系的复杂性降至最低。首选在执行环境启动时可以快速加载的更简单的框架。
-
将部署程序包大小精简为只包含运行时必要的部分。这样会减少调用前下载和解压缩部署程序包所需的时间。
-
利用执行环境重用来提高函数性能。连接软件开发工具包 (SDK) 客户端和函数处理程序之外的数据库,并在
/tmp
目录中本地缓存静态资产。由函数的同一实例处理的后续调用可重用这些资源。这样就可以通过缩短函数运行时间来节省成本。为了避免调用之间潜在的数据泄露,请不要使用执行环境来存储用户数据、事件或其他具有安全影响的信息。如果您的函数依赖于无法存储在处理程序的内存中的可变状态,请考虑为每个用户创建单独的函数或单独的函数版本。
-
使用 keep-alive 指令来维护持久连接。Lambda 会随着时间的推移清除空闲连接。在调用函数时尝试重用空闲连接会导致连接错误。要维护您的持久连接,请使用与运行时关联的 keep-alive 指令。有关示例,请参阅在 Node.js 中通过 Keep-Alive 重用连接。
-
使用环境变量将操作参数传递给函数。例如,您在写入 Amazon S3 存储桶时,不应对要写入的存储桶名称进行硬编码,而应将存储桶名称配置为环境变量。
-
避免在 Lambda 函数中使用递归调用,在这种情况下,函数会调用自己或启动可能再次调用该函数的进程。这可能会导致意想不到的函数调用量和升级成本。如果您看到意外的调用量,请立即将函数保留并发设置为
0
来限制对函数的所有调用,同时更新代码。 -
Lambda 函数代码中不要使用非正式的非公有 API。对于 AWS Lambda 托管式运行时,Lambda 会定期为 Lambda 的内部 API 应用安全性和功能更新。这些内部 API 更新可能不能向后兼容,会导致意外后果,例如,假设您的函数依赖于这些非公有 API,则调用会失败。请参阅 API 参考以查看公开发布的 API 列表。
-
编写幂等代码。为您的函数编写幂等代码可确保以相同的方式处理重复事件。您的代码应该正确验证事件并优雅地处理重复事件。有关更多信息,请参阅如何使我的 Lambda 函数具有幂等性?
。