

# 使用 Node.js 构建 Lambda 函数
<a name="lambda-nodejs"></a>

您可以使用 Node.js 在 Amazon Lambda 中运行 JavaScript 代码。Lambda 可为 Node.js 提供[运行时](lambda-runtimes.md)，用于运行代码来处理事件。您的代码在包含 适用于 JavaScript 的 Amazon SDK 的环境中运行，其中包含来自您管理的 Amazon Identity and Access Management (IAM) 角色的凭证。要了解有关 Node.js 运行时随附的 SDK 版本的更多信息，请参阅 [包含运行时的 SDK 版本](#nodejs-sdk-included)。

Lambda 支持以下 Node.js 运行时。<a name="nodejs-supported-runtimes"></a>


| 名称 | 标识符 | 操作系统 | 弃用日期 | 阻止函数创建 | 阻止函数更新 | 
| --- | --- | --- | --- | --- | --- | 
|  Node.js 24  |  `nodejs24.x`  |  Amazon Linux 2023  |   2028 年 4 月 30 日   |   2028 年 6 月 1 日   |   2028 年 7 月 1 日   | 
|  Node.js 22  |  `nodejs22.x`  |  Amazon Linux 2023  |   2027 年 4 月 30 日   |   2027 年 6 月 1 日   |   2027 年 7 月 1 日   | 
|  Node.js 20  |  `nodejs20.x`  |  Amazon Linux 2023  |   2026 年 4 月 30 日   |   2026 年 8 月 31 日   |   Sep 30, 2026   | 

**创建 Node.js 函数**

1. 打开 [Lambda 控制台](https://console.amazonaws.cn/lambda)。

1. 选择 **Create function**（创建函数）。

1. 配置以下设置：
   + **函数名称**：输入函数名称。
   + **运行时系统**：选择 **Node.js 24.x**。

1. 选择**创建函数**。

控制台将使用名为 `index.mjs` 的源文件创建一个 Lambda 函数。您可以在内置代码编辑器中编辑此文件并添加更多文件。在**部署**部分，选择**部署**以更新函数的代码。然后，要运行您的代码，请在**测试事件**部分中选择**创建测试事件**。

`index.mjs` 文件会导出一个名为 `handler` 的函数，此函数将接受事件对象和上下文对象。这是 Lambda 在调用函数时调用的[处理函数](nodejs-handler.md)。Node.js 函数运行时从 Lambda 获取调用事件并将其传递到处理程序。在函数配置中，处理程序值为 `index.handler`。

保存函数代码时，Lambda 控制台会创建一个 .zip 文件归档部署包。在控制台外部开发函数代码时（使用 IDE），您需要[创建部署程序包](nodejs-package.md)将代码上载到 Lambda 函数。

除了调用事件之外，函数运行时还将上下文对象传递给处理程序。[上下文对象](nodejs-context.md)包含有关调用、函数和执行环境的其他信息。环境变量中提供了更多信息。

您的 Lambda 函数附带了 CloudWatch Logs 日志组。函数运行时会将每次调用的详细信息发送到 CloudWatch Logs。该运行时会中继调用期间[函数输出的任何日志](nodejs-logging.md)。如果您的函数返回错误，则 Lambda 将为错误设置格式，并将其返回给调用方。

**Topics**
+ [

## 包含运行时的 SDK 版本
](#nodejs-sdk-included)
+ [

## 对 TCP 连接使用“保持连接”
](#nodejs-keep-alive)
+ [

## 正在加载 CA 证书
](#nodejs-certificate-loading)
+ [

## 实验性 Node.js 功能
](#nodejs-experimental-features)
+ [

# 定义采用 Node.js 的 Lambda 函数处理程序
](nodejs-handler.md)
+ [

# 使用 .zip 文件归档部署 Node.js Lambda 函数
](nodejs-package.md)
+ [

# 使用容器映像部署 Node.js Lambda 函数
](nodejs-image.md)
+ [

# 使用 Node.js Lambda 函数的层
](nodejs-layers.md)
+ [

# 使用 Lambda 上下文对象检索 Node.js 函数信息
](nodejs-context.md)
+ [

# Node.js Lambda 函数日志记录和监控
](nodejs-logging.md)
+ [

# 在 Amazon Lambda 中检测 Node.js 代码
](nodejs-tracing.md)

## 包含运行时的 SDK 版本
<a name="nodejs-sdk-included"></a>

所有[支持的 Lambda Node.js 运行时](#nodejs-supported-runtimes)都包含 适用于 JavaScript 的 Amazon SDK v3 的特定次要版本，而不是[最新版本](https://github.com/aws/aws-sdk-js-v3/releases)。运行时中包含的特定次要版本取决于运行时版本和您的 Amazon Web Services 区域。要查找您正在使用的运行时中包含的 SDK 特定版本，请使用以下代码创建 Lambda 函数。

**Example index.mjs**  

```
import packageJson from '@aws-sdk/client-s3/package.json' with { type: 'json' };

export const handler = async () => ({ version: packageJson.version });
```
这会返回以下格式的响应：  

```
{
  "version": "3.632.0"
}
```

有关更多信息，请参阅 [在处理程序中使用适用于 JavaScript v3 的 SDK](nodejs-handler.md#nodejs-example-sdk-usage)。

## 对 TCP 连接使用“保持连接”
<a name="nodejs-keep-alive"></a>

默认的 Node.js HTTP/HTTPS 代理会为每个新请求创建一个新的 TCP 连接。为了避免建立新连接的成本，所有[受支持的 Node.js 运行时](#nodejs-supported-runtimes)都默认启用“保持活动”。“保持连接”可以减少使用 SDK 进行多次 API 调用的 Lambda 函数的请求时间。

要禁用“保持连接”，请参阅《Amazon SDK for JavaScript 3.x Developer Guide**》中的 [Reusing connections with keep-alive in Node.js](https://docs.amazonaws.cn/sdk-for-javascript/v3/developer-guide/node-reusing-connections.html)。有关使用“保持连接”的更多信息，请参阅 Amazon 开发工具博客上的 [HTTP keep-alive is on by default in modular Amazon SDK for JavaScript](https://www.amazonaws.cn/blogs/developer/http-keep-alive-is-on-by-default-in-modular-aws-sdk-for-javascript/)。

## 正在加载 CA 证书
<a name="nodejs-certificate-loading"></a>

对于 Node.js 18 之前的 Node.js 运行时系统版本，Lambda 会自动加载特定于 Amazon 的 CA（证书颁发机构）证书，让您更轻松地创建与其他 Amazon Web Services 服务 交互的函数。例如，Lambda 包括验证安装在 Amazon RDS 数据库上的[服务器身份证书](https://docs.amazonaws.cn/AmazonRDS/latest/UserGuide/UsingWithRDS.SSL.html)所必需的 Amazon RDS 证书。这种行为可能会对冷启动期间的性能产生影响。

从 Node.js 20 开始，Lambda 默认不再加载其他 CA 证书。Node.js 20 运行时系统包含一个证书文件，其中所有 Amazon CA 证书都位于 `/var/runtime/ca-cert.pem`。要从 Node.js 18 及更早版本的运行时系统恢复相同的行为，请将 `NODE_EXTRA_CA_CERTS` [环境变量](configuration-envvars.md)设置为 `/var/runtime/ca-cert.pem`。

为了获得最佳性能，我们建议仅将所需的证书与部署包捆绑在一起，并通过 `NODE_EXTRA_CA_CERTS` 环境变量进行加载。证书文件应包含一个或多个 PEM 格式的可信根证书或中间 CA 证书。例如，对于 RDS，将所需的证书与代码一起包含在 `certificates/rds.pem`。然后，通过将 `NODE_EXTRA_CA_CERTS` 设置为 `/var/task/certificates/rds.pem` 来加载证书。

## 实验性 Node.js 功能
<a name="nodejs-experimental-features"></a>

上游 Node.js 语言版本默认启用一些实验性功能。Lambda 禁用这些功能以确保运行时稳定且性能一致。下表列出了 Lambda 禁用的实验性功能。


| 实验性功能 | 支持的 Node.js 版本 | Lambda 应用的 Node.js 标志 | 要重新启用的 Lambda 标志 | 
| --- | --- | --- | --- | 
|  支持在 ES 模块中使用 require 导入模块  |  Node.js 20、Node.js 22  |  `--no-experimental-require-module`  |  `--experimental-require-module`  | 
|  支持自动检测 ES 与 CommonJS 模块  |  Node.js 22  |  `--no-experimental-detect-module`  |  `--experimental-detect-module`  | 

要启用已禁用的实验性功能，请在 `NODE_OPTIONS` 环境变量中设置重新启用标志。例如，要启用 ES 模块 require 支持，请将 `NODE_OPTIONS` 设置为 `--experimental-require-module`。Lambda 检测到此覆盖并移除相应的禁用标志。

**重要**  
 使用实验性功能可能会导致不稳定和性能问题。这些功能可能会在未来的 Node.js 版本中被更改或移除。使用实验性功能的函数不符合 Lambda 服务水平协议 (SLA) 或 Amazon Web Services 支持 的资格。

# 定义采用 Node.js 的 Lambda 函数处理程序
<a name="nodejs-handler"></a>

Lambda 函数*处理程序*是函数代码中处理事件的方法。当调用函数时，Lambda 运行处理程序方法。您的函数会一直运行，直到处理程序返回响应、退出或超时。

本页介绍了如何使用 Node.js Lambda 函数处理程序，包括项目设置选项、命名约定和最佳实践。本页还包括 Node.js Lambda 函数的示例，在示例中该函数接收订单信息，生成文本文件收据，然后将此文件放入 Amazon Simple Storage Service（Amazon S3）存储桶中。有关如何在编写函数后部署函数的信息，请参阅[使用 .zip 文件归档部署 Node.js Lambda 函数](nodejs-package.md)或[使用容器映像部署 Node.js Lambda 函数](nodejs-image.md)。

**Topics**
+ [

## 设置 Node.js 处理程序项目
](#nodejs-handler-setup)
+ [

## 示例 Node.js Lambda 函数代码
](#nodejs-example-code)
+ [

## CommonJS 和 ES 模块
](#nodejs-commonjs-es-modules)
+ [

## Node.js 初始化
](#nodejs-initialization)
+ [

## 处理程序命名约定
](#nodejs-handler-naming)
+ [

## 定义和访问输入事件对象
](#nodejs-example-input)
+ [

## Node.js 函数的有效处理程序模式
](#nodejs-handler-signatures)
+ [

## 在处理程序中使用适用于 JavaScript v3 的 SDK
](#nodejs-example-sdk-usage)
+ [

## 评估环境变量
](#nodejs-example-envvars)
+ [

## 使用全局状态
](#nodejs-handler-state)
+ [

## Node.js Lambda 函数的代码最佳实践
](#nodejs-best-practices)

## 设置 Node.js 处理程序项目
<a name="nodejs-handler-setup"></a>

有多种方法可初始化 Node.js Lambda 项目。例如，您可以使用 `npm` 创建标准 Node.js 项目、创建 [Amazon SAM 应用程序](https://docs.amazonaws.cn/serverless-application-model/latest/developerguide/using-sam-cli-init.html#using-sam-cli-init-new)或创建 [Amazon CDK 应用程序](lambda-cdk-tutorial.md#lambda-cdk-step-1)。

使用 `npm` 创建项目：

```
npm init
```

此命令将初始化项目，并生成管理项目元数据和依赖项的 `package.json` 文件。

您的函数代码位于 `.js` 或 `.mjs` JavaScript 文件中。在以下示例中，我们将此文件命名为 `index.mjs`，因为其使用了 ES 模块处理程序。Lambda 同时支持 ES 模块和 CommonJS 处理程序。有关更多信息，请参阅 [CommonJS 和 ES 模块](#nodejs-commonjs-es-modules)。

典型的 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 函数代码
<a name="nodejs-example-code"></a>

以下示例 Lambda 函数代码接收有关订单的信息，生成文本文件接收，并将此文件放入 Amazon S3 存储桶中。

**Example 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 函数所需的库，例如 [Amazon SDK 客户端](https://docs.amazonaws.cn/sdk-for-javascript/v3/developer-guide/the-request-object.html)。
+ `const s3Client` 声明：用于在处理程序函数之外初始化 [Amazon S3 客户端](https://docs.amazonaws.cn/AWSJavaScriptSDK/v3/latest/client/s3/)。这会导致 Lambda 在[初始化阶段](lambda-runtime-environment.md#runtimes-lifecycle-ib)运行此代码，并保留客户端以供[多次调用时重复使用](lambda-runtime-environment.md#execution-environment-reuse)。
+ JSDoc 注释块：使用 [JSDoc 注释](https://jsdoc.app/about-getting-started)为处理程序定义输入和输出类型。
+ `export const handler`：这是 Lambda 调用的主要处理程序函数。部署函数时，请为[处理程序](https://docs.amazonaws.cn/lambda/latest/api/API_CreateFunction.html#lambda-CreateFunction-request-Handler)属性指定 `index.handler`。`Handler` 属性的值是文件的名称和导出的处理程序方法的名称（由点分隔）。
+ `uploadReceiptToS3` 函数：这是主要处理程序函数引用的帮助函数。

要使此函数正常运行，其[执行角色](lambda-intro-execution-role.md)必须允许 `s3:PutObject` 操作。此外，请确保您定义了 `RECEIPT_BUCKET` 环境变量。成功调用后，Amazon S3 存储桶应包含接收文件。

## CommonJS 和 ES 模块
<a name="nodejs-commonjs-es-modules"></a>

Node.js 支持两个模块系统：CommonJS 和 ECMAScript 模块（ES 模块）。Lambda 建议使用 ES 模块，因为它支持顶层的 await 语句，这使得异步任务能够在[执行环境初始化](#nodejs-initialization)期间完成。

Node.js 将带有 `.cjs` 文件扩展名的文件视为 CommonJS 模块，而 `.mjs` 扩展程序则表示 ES 模块。默认情况下，Node.js 将带有 `.js` 文件扩展名的文件视为 CommonJS 模块。通过在函数的 `package.json` 文件中将 `type` 指定为 `module`，您可以将 Node.js 配置为将 `.js` 文件视为 ES 模块。您可以在 Lambda 中配置 Node.js，使其能够通过在 `NODE_OPTIONS` 环境变量中添加 `—experimental-detect-module` 标识来自动检测一个 `.js` 文件应被视为 CommonJS 还是 ES 模块格式。有关更多信息，请参阅[实验性 Node.js 特征](lambda-nodejs.md#nodejs-experimental-features)。

以下示例显示了使用 ES 模块和 CommonJS 模块编写的函数处理程序。本页上的其余示例均使用 ES 模块。

------
#### [ ES module example ]

**Example – ES 模块处理程序**  

```
const url = "https://aws.amazon.com/";

export const handler = async(event) => {
    try {
        const res = await fetch(url);
        console.info("status", res.status);
        return res.status;
    }
    catch (e) {
        console.error(e);
        return 500;
    }
};
```

------
#### [ CommonJS module example ]

**Example – CommonJS 模块处理程序**  

```
const https = require("https");
let url = "https://aws.amazon.com/";

exports.handler = async function (event) {
  let statusCode;
  await new Promise(function (resolve, reject) {
    https.get(url, (res) => {
        statusCode = res.statusCode;
        resolve(statusCode);
      }).on("error", (e) => {
        reject(Error(e));
      });
  });
  console.log(statusCode);
  return statusCode;
};
```

------

## Node.js 初始化
<a name="nodejs-initialization"></a>

Node.js 使用一种非阻止式 I/O 模型，该模型通过事件循环支持高效的异步操作。例如，如果 Node.js 进行网络调用，则该函数将继续处理其他操作，而不会因等待网络响应而阻塞。当收到网络响应后，会将其放入回调队列中。当前任务完成时，便会处理队列中的任务。

Lambda 建议使用顶层的 await 语句，以使执行环境初始化期间启动的异步任务在初始化期间完成。初始化期间未完成的异步任务通常会在第一次函数调用期间运行。这可能会导致意外行为或错误。例如，您的函数初始化可能会进行网络调用，以从 Amazon Parameter Store 中获取参数。如果在初始化过程中未完成此任务，则调用时该值可能会为 null。初始化和调用之间也可能存在延迟，这可能会在时间敏感的操作中触发错误。特别是，Amazon 服务调用可以依赖于时间敏感的请求签名，如果在初始化阶段未完成调用，则会导致服务调用失败。在初始化阶段完成任务通常会提升冷启动性能，而使用预置并发时，首次调用的性能也会有所提升。有关更多信息，请参阅博客文章[在 Amazon Lambda 中使用 Node.js ES 模块和顶层 await 语句](https://www.amazonaws.cn/blogs/compute/using-node-js-es-modules-and-top-level-await-in-aws-lambda)。

## 处理程序命名约定
<a name="nodejs-handler-naming"></a>

配置函数时，[处理程序](https://docs.amazonaws.cn/lambda/latest/api/API_CreateFunction.html#lambda-CreateFunction-request-Handler)设置的值是文件的名称和导出的处理程序方法的名称（由点分隔）。控制台中创建的函数的默认值为 `index.handler`，这也是本指南所用示例的值。这表示从 `index.js` 或 `index.mjs` 文件中导出的 `handler` 方法。

如果您在控制台中使用不同的文件名或函数处理程序名称创建函数，则必须编辑默认处理程序名称。

**更改函数处理程序名称（控制台）**

1. 打开 Lambda 控制台的[函数](https://console.amazonaws.cn/lambda/home#/functions)页面，然后选择一个函数。

1. 选择**节点**选项卡。

1. 向下滚动到**运行时设置**窗格并选择**编辑**。

1. 在**处理程序**中，输入函数处理程序的新名称。

1. 选择**保存**。

## 定义和访问输入事件对象
<a name="nodejs-example-input"></a>

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 函数的有效处理程序模式
<a name="nodejs-handler-signatures"></a>

建议您使用 [async/await](https://docs.amazonaws.cn/sdk-for-javascript/v3/developer-guide/using-async-await.html) 来声明函数处理程序，而不是使用[回调](https://docs.amazonaws.cn/sdk-for-javascript/v3/developer-guide/using-a-callback-function.html)。Async/await 是一种简洁、易读的异步代码编写方式，无需使用嵌套回调或链式承诺。使用 Async/await 时，您编写的代码看起来与同步代码类似，同时仍然是异步和非阻止式的。

### 异步函数处理程序（推荐）
<a name="nodejs-handler-async"></a>

`async` 关键字会将函数标记为异步，`await` 关键字会暂停函数的执行，直到 `Promise` 完成解析为止。处理程序接受以下参数：
+ `event`：包含传递给您函数的输入数据。
+ `context`：包含有关调用、函数和执行环境的信息。有关更多信息，请参阅 [使用 Lambda 上下文对象检索 Node.js 函数信息](nodejs-context.md)。

以下为 async/await 模式的有效签名：

```
export const handler = async (event) => { };
```

```
export const handler = async (event, context) => { };
```

### 同步函数处理程序
<a name="nodejs-handler-synchronous"></a>

如果您的函数不执行任何异步任务，则可以使用同步函数处理程序，并采用以下函数签名之一：

```
export const handler = (event) => { };
```

```
export const handler = (event, context) => { };
```

### 响应流式处理函数处理程序
<a name="nodejs-handler-response-streaming"></a>

Lambda 支持使用 Node.js 进行响应流式处理。响应流式处理函数处理程序使用 `awslambda.streamifyResponse()` 修饰器并采用 3 个参数：`event`、`responseStream` 和 `context`。函数签名是：

```
export const handler = awslambda.streamifyResponse(async (event, responseStream, context) => { });
```

有关更多信息，请参阅 [Lambda 函数的响应流](configuration-response-streaming.md)。

### 基于回调的函数处理程序
<a name="nodejs-handler-callback"></a>

**注意**  
基于回调的函数处理程序仅在 Node.js 22 及以下版本中才被支持。从 Node.js 24 开始，应使用异步函数处理程序实施异步任务。

基于回调的函数处理程序必须使用事件、上下文和回调参数。示例：

```
export const handler = (event, context, callback) => { };
```

回调函数需要一个 `Error` 和一个响应，该响应必须是 JSON 可序列化的。函数会一直执行，直到[事件循环](https://nodejs.org/en/docs/guides/event-loop-timers-and-nexttick/)为空或函数超时为止。在完成所有事件循环任务之前，不会将响应发送给调用方。如果函数超时，则会返回 error。可以通过将 [context.callbackWaitsForEmptyEventLoop](nodejs-context.md) 设置为 false，从而将运行时配置为立即发送响应。

**Example – 包含 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
<a name="nodejs-example-sdk-usage"></a>

通常，您将使用 Lambda 函数与其他 Amazon 资源进行交互或对其进行更新。与此类资源最简单的交互方法是使用 适用于 JavaScript 的 Amazon SDK。所有[支持的 Lambda Node.js 运行时](lambda-nodejs.md#nodejs-supported-runtimes)都包含[适用于 JavaScript 版本 3 的 SDK](https://docs.amazonaws.cn/AWSJavaScriptSDK/v3/latest/introduction/)。但是，强烈建议您在部署包中包含所需的 Amazon SDK 客户端。这样可以最大限度地提高未来 Lambda 运行时更新期间的[向后兼容性](runtimes-update.md#runtime-update-compatibility)。只有在无法包含其他程序包时（例如，在 Amazon CloudFormation 模板中使用 Lambda 控制台代码编辑器或内联代码时），才依赖运行时提供的 SDK。

要向函数添加 SDK 依赖项，请使用适用于所需特定 SDK 客户端的 `npm install` 命令。在示例代码中，我们使用了 [Amazon S3 客户端](https://docs.amazonaws.cn/AWSJavaScriptSDK/v3/latest/client/s3/)。在包含 `package.json` 文件的目录中，运行以下命令添加此依赖项：

```
npm install @aws-sdk/client-s3
```

在函数代码中，导入所需的客户端和命令，如示例函数所示：

```
import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';
```

然后，初始化 [Amazon S3 客户端](https://docs.amazonaws.cn/AWSJavaScriptSDK/v3/latest/client/s3/)：

```
const s3Client = new S3Client();
```

在此示例中，我们在主处理程序函数之外初始化了 Amazon S3 客户端，以免每次调用函数时都必须对其进行初始化。初始化 SDK 客户端后，就可以使用它为 Amazon 服务发出 API 调用。示例代码按如下方式调用 Amazon S3 [PutObject](https://docs.amazonaws.cn/AWSJavaScriptSDK/v3/latest/client/s3/command/PutObjectCommand/) API：

```
const command = new PutObjectCommand({
    Bucket: bucketName,
    Key: key,
    Body: receiptContent
});
```

## 评估环境变量
<a name="nodejs-example-envvars"></a>

在处理程序代码中，您可以使用 `process.env` 引用任意[环境变量](configuration-envvars.md)。在此示例中，我们使用以下代码行来引用已定义的 `RECEIPT_BUCKET` 环境变量：

```
// Access environment variables
const bucketName = process.env.RECEIPT_BUCKET;
if (!bucketName) {
    throw new Error('RECEIPT_BUCKET environment variable is not set');
}
```

## 使用全局状态
<a name="nodejs-handler-state"></a>

在首次调用您的函数之前，Lambda 会在[初始化阶段](lambda-runtime-environment.md#runtimes-lifecycle-ib)运行您的静态代码。初始化期间创建的资源在两次调用之间保留在内存中，因此您可以避免每次调用函数时都必须创建这些资源的情况。

在示例代码中，S3 客户端初始化代码位于主处理程序之外。运行时会在函数处理第一个事件之前初始化客户端，之后所有的调用都可以重复使用该客户端。

## Node.js Lambda 函数的代码最佳实践
<a name="nodejs-best-practices"></a>

构建 Lambda 函数时请遵循以下准则：
+ **从核心逻辑中分离 Lambda 处理程序。**这样您可以创建更容易进行单元测试的函数。
+ **控制函数部署包中的依赖关系。**Amazon Lambda 执行环境包含许多库。对于 Node.js 和 Python 运行时，其中包括 Amazon SDK。Lambda 会定期更新这些库，以支持最新的功能组合和安全更新。这些更新可能会使 Lambda 函数的行为发生细微变化。要完全控制您的函数所用的依赖项，请使用部署包来打包所有依赖项。
+ **将依赖关系的复杂性降至最低。**首选在[执行环境](lambda-runtime-environment.md)启动时可以快速加载的更简单的框架。
+ **将部署包大小精简为只包含运行时必要的部分。**这样会减少调用前下载和解压缩部署包所需的时间。

**利用执行环境重用来提高函数性能。**连接软件开发工具包 (SDK) 客户端和函数处理程序之外的数据库，并在 `/tmp` 目录中本地缓存静态资产。由函数的同一实例处理的后续调用可重用这些资源。这样就可以通过缩短函数运行时间来节省成本。

为了避免调用之间潜在的数据泄露，请不要使用执行环境来存储用户数据、事件或其他具有安全影响的信息。如果您的函数依赖于无法存储在处理程序的内存中的可变状态，请考虑为每个用户创建单独的函数或单独的函数版本。

**使用 keep-alive 指令来维护持久连接。**Lambda 会随着时间的推移清除空闲连接。在调用函数时尝试重用空闲连接会导致连接错误。要维护您的持久连接，请使用与运行时关联的 keep-alive 指令。有关示例，请参阅[在 Node.js 中通过 Keep-Alive 重用连接](https://docs.amazonaws.cn/sdk-for-javascript/v3/developer-guide/node-reusing-connections.html)。

**使用[环境变量](configuration-envvars.md)将操作参数传递给函数。**例如，您在写入 Amazon S3 存储桶时，不应对要写入的存储桶名称进行硬编码，而应将存储桶名称配置为环境变量。

**避免在 Lambda 函数中使用递归调用**，在这种情况下，函数会调用自己或启动可能再次调用该函数的进程。这可能会导致意想不到的函数调用量和升级成本。如果您看到意外的调用量，请立即将函数保留并发设置为 `0` 来限制对函数的所有调用，同时更新代码。

Lambda 函数代码中**不要使用非正式的非公有 API**。对于 Amazon Lambda 托管式运行时，Lambda 会定期为 Lambda 的内部 API 应用安全性和功能更新。这些内部 API 更新可能不能向后兼容，会导致意外后果，例如，假设您的函数依赖于这些非公有 API，则调用会失败。请参阅 [API 参考](https://docs.amazonaws.cn/lambda/latest/api/welcome.html)以查看公开发布的 API 列表。

**编写幂等代码。**为您的函数编写幂等代码可确保以相同的方式处理重复事件。您的代码应该正确验证事件并优雅地处理重复事件。有关更多信息，请参阅[如何使我的 Lambda 函数具有幂等性？](https://www.amazonaws.cn/premiumsupport/knowledge-center/lambda-function-idempotent/)。

# 使用 .zip 文件归档部署 Node.js Lambda 函数
<a name="nodejs-package"></a>

 Amazon Lambda 函数的代码包含一个 .js 或 .mjs 文件，其中包含函数的处理程序代码，以及代码所依赖的任何其他包和模块。要将此函数部署到 Lambda，您可以使用*部署包*。此包可以是 .zip 文件归档或容器映像。有关在 Node.js 中使用容器映像的更多信息，请参阅[使用容器映像部署 Node.js Lambda 函数](https://docs.amazonaws.cn/lambda/latest/dg/nodejs-image.html)。

 要创建 .zip 文件归档格式的部署包，可以使用命令行工具内置的 .zip 文件归档实用工具或任何其他 .zip 文件实用工具（例如 [7zip](https://www.7-zip.org/download.html)）。以下各部分中显示的示例假设您在 Linux 或 macOS 环境中使用命令行 `zip` 工具。要在 Windows 中使用相同命令，您可以安装 [Windows Subsystem for Linux](https://docs.microsoft.com/en-us/windows/wsl/install-win10)，以获取 Windows 集成版本的 Ubuntu 和 Bash。

 请注意，Lambda 使用 POSIX 文件权限，因此在创建 .zip 文件归档之前，您可能需要[为部署包文件夹设置权限](https://www.amazonaws.cn/premiumsupport/knowledge-center/lambda-deployment-package-errors/)。

**Topics**
+ [

## Node.js 中的运行时系统依赖项
](#nodejs-package-dependencies)
+ [

## 创建不含依赖项的 .zip 部署包
](#nodejs-package-create-no-dependencies)
+ [

## 创建含依赖项的 .zip 部署包
](#nodejs-package-create-dependencies)
+ [

## 为依赖项创建 Node.js 层
](#nodejs-package-dependencies-layers)
+ [

## 依赖项搜索路径和包含运行时系统的库
](#nodejs-package-searchpath)
+ [

## 使用 .zip 文件创建和更新 Node.js Lambda 函数
](#nodejs-package-create-update)

## Node.js 中的运行时系统依赖项
<a name="nodejs-package-dependencies"></a>

 对于使用 Node.js 运行时系统的 Lambda 函数，依赖项可以是任何 Node.js 模块。Node.js 运行时系统包括许多常用库以及一个 适用于 JavaScript 的 Amazon SDK 版本。所有[支持的 Node.js 运行时](lambda-nodejs.md#nodejs-supported-runtimes)都包含 SDK 版本 3。要使用 SDK 版本 2，您必须将 SDK 添加到 .zip 文件部署包中。要查找您正在使用的运行时中包含的 SDK 的具体版本，请参阅[包含运行时的 SDK 版本](lambda-nodejs.md#nodejs-sdk-included)。

 Lambda 会定期更新 Node.js 运行时系统中的开发工具包库，以包含最新更新和安全补丁。Lambda 还会对运行时系统中包含的其他库应用安全补丁和更新。要完全控制包中的依赖项，您可以将任何包含运行时系统依赖项的首选版本添加到部署包中。例如，如果您想使用适用于 JavaScript 的开发工具包的特定版本，则可以将其作为依赖项包含在.zip 文件中。有关向.zip 文件添加包含运行时系统的依赖项的更多信息，请参阅 [依赖项搜索路径和包含运行时系统的库](#nodejs-package-searchpath)。

 在 [Amazon 责任共担模式](lambda-runtimes.md#runtimes-shared-responsibility)下，您负责管理函数部署包中的所有依赖项。这包括应用更新和安全补丁。要更新函数部署包中的依赖项，请先创建一个新的 .zip 文件，然后将其上传到 Lambda 中。有关更多信息，请参阅 [创建含依赖项的 .zip 部署包](#nodejs-package-create-dependencies) 和 [使用 .zip 文件创建和更新 Node.js Lambda 函数](#nodejs-package-create-update)。

## 创建不含依赖项的 .zip 部署包
<a name="nodejs-package-create-no-dependencies"></a>

 如果除了包含在 Lamba 运行时系统中的库外，您的函数代码没有其他依赖项，则 .zip 文件仅包含带有函数处理程序代码的 `index.js` 或 `index.mjs` 文件。使用您的首选 zip 实用工具创建一个 .zip 文件，并将 `index.js` 或 `index.mjs` 文件置于根目录中。如果包含您处理程序代码的文件不在 .zip 文件的根目录中，Lambda 将无法运行代码。

 要了解如何部署 .zip 文件以创建新的 Lambda 函数或更新现有函数，请参阅 [使用 .zip 文件创建和更新 Node.js Lambda 函数](#nodejs-package-create-update)。

## 创建含依赖项的 .zip 部署包
<a name="nodejs-package-create-dependencies"></a>

如果函数代码依赖未包含在 Lamba Node.js 运行时系统中的程序包或模块，您可以使用函数代码将这些依赖项添加到 .zip 文件中，也可以使用 [Lambda 层](chapter-layers.md)。本部分中的说明向您展示了如何将依赖项包含在 .zip 部署包中。有关如何将依赖项包含在层中的说明，请参阅 [为依赖项创建 Node.js 层](#nodejs-package-dependencies-layers)。

以下示例 CLI 命令将创建名为 `my_deployment_package.zip` 的 .zip 文件，其中包含 `index.js` 或 `index.mjs` 文件，以及您的函数处理程序代码及其依赖项。在示例中，您要使用 npm 程序包管理器来安装依赖项。

**创建部署包**

1. 导航到包含 `index.js` 或 `index.mjs` 源代码文件的项目目录。在此示例中，该目录名为 `my_function`。

   ```
   cd my_function
   ```

1. 使用 `npm install` 命令在 `node_modules` 目录中安装函数所需的库。在此示例中，您要安装 Amazon X-Ray SDK for Node.js。

   ```
   npm install aws-xray-sdk
   ```

   这将创建一个类似于下面的文件夹结构：

   ```
   ~/my_function
   ├── index.mjs
   └── node_modules
       ├── async
       ├── async-listener
       ├── atomic-batcher
       ├── aws-sdk
       ├── aws-xray-sdk
       ├── aws-xray-sdk-core
   ```

   您还可以将自己创建的自定义模块添加到部署包中。在 `node_modules` 下创建一个以模块命名的目录，然后将自定义编写程序包保存在此处。

1. 在根目录下创建一个包含您的项目文件夹内容的 .zip 文件。使用 `r` （递归）选项来确保 zip 压缩子文件夹。

   ```
   zip -r my_deployment_package.zip .
   ```

## 为依赖项创建 Node.js 层
<a name="nodejs-package-dependencies-layers"></a>

本部分中的说明旨在向您展示如何将依赖项包含在层中。有关如何将依赖项包含在部署包中的说明，请参阅 [创建含依赖项的 .zip 部署包](#nodejs-package-create-dependencies)。

当您向函数添加层时，Lambda 会将层内容加载到该执行环境的 `/opt` 目录中。对于每个 Lambda 运行时系统，`PATH` 变量都包括 `/opt` 目录中的特定文件夹路径。为确保 Lambda 能够获取层内容，层 .zip 文件应在以下任何一个文件夹路径中具有依赖项：
+ `nodejs/node_modules`
+ `nodejs/node18/node_modules (NODE_PATH)`
+ `nodejs/node20/node_modules (NODE_PATH)`
+ `nodejs/node22/node_modules (NODE_PATH)`

例如，层.zip 文件结构可能如下所示：

```
xray-sdk.zip
└ nodejs/node_modules/aws-xray-sdk
```

此外，Lambda 会自动检测 `/opt/lib` 目录中的任何库，以及 `/opt/bin` 目录中的任何二进制文件。为确保 Lambda 正确获取层内容，还可以创建包含以下结构的层：

```
custom-layer.zip
└ lib
    | lib_1
    | lib_2
└ bin
    | bin_1
    | bin_2
```

打包层后，请参阅 [在 Lambda 中创建和删除层](creating-deleting-layers.md) 和 [向函数添加层](adding-layers.md) 以完成层设置。

## 依赖项搜索路径和包含运行时系统的库
<a name="nodejs-package-searchpath"></a>

Node.js 运行时系统包括许多常用库以及一个 适用于 JavaScript 的 Amazon SDK 版本。如果您想使用包含运行时系统的库的不同版本，可以通过将其与自己的函数捆绑或将其作为依赖项添加到部署包中来实现。例如，您可以通过将开发工具包添加到 .zip 部署包中来使用其他版本的开发工具包。您也可以将其包含在函数的 [Lambda 层](chapter-layers.md)中。

在代码中使用 `import` 或 `require` 语句时，Node.js 运行时系统会搜索 `NODE_PATH` 路径中的目录，直到找到相应模块。默认情况下，运行时系统搜索的第一个位置是解压缩并安装 .zip 部署包的目录 (`/var/task`)。如果在部署包中包含运行时系统的库的某个版本，则此版本将优先于运行时系统中包含的版本。部署包中的依赖项也优先于层中的依赖项。

向层添加依赖项时，Lambda 会将其提取到 `/opt/nodejs/nodexx/node_modules` 中，其中 `nodexx` 表示正在使用的运行时系统版本。在搜索路径中，此目录优先于包含运行时系统的库的目录 (`/var/lang/lib/node_modules`)。因此，函数层中的库优先于运行时系统中包含的版本。

通过添加以下代码行，您可以查看 Lambda 函数的完整搜索路径。

```
console.log(process.env.NODE_PATH)
```

您还可以在 .zip 程序包内的单独文件夹中添加依赖项。例如，您可以将自定义模块添加到 .zip 程序包中名为 `common` 的文件夹中。解压缩并安装 .zip 程序包后，此文件夹将放置在 `/var/task` 目录中。要在代码中使用 .zip 部署包中某个文件夹的依赖项，请使用 `import { } from` 或 `const { } = require()` 语句，具体取决于您使用的是 CJS 还是 ESM 模块解析。例如：

```
import { myModule } from './common'
```

如果您将代码与 `esbuild`、`rollup` 或类似内容捆绑在一起，则函数使用的依赖项将捆绑在一个或多个文件中。我们建议尽量使用此方法来提供依赖项。与向部署包添加依赖项相比，由于减少了 I/O 操作，捆绑代码可以提高性能。

## 使用 .zip 文件创建和更新 Node.js Lambda 函数
<a name="nodejs-package-create-update"></a>

 创建 .zip 部署包后，您可以用其创建新的 Lambda 函数或更新现有的 Lambda 函数。您可以使用 Lambda 控制台、Amazon Command Line Interface 和 Lambda API 部署 .zip 程序包。您也可以使用 Amazon Serverless Application Model（Amazon SAM）和 Amazon CloudFormation 创建和更新 Lambda 函数。

Lambda 的 .zip 部署包的最大大小为 250MB（已解压缩）。请注意，此限制适用于您上传的所有文件（包括任何 Lambda 层）的组合大小。

Lambda 运行时需要权限才能读取部署包中的文件。在 Linux 权限八进制表示法中，Lambda 对于不可执行文件（rw-r--r--）需要 644 个权限，对于目录和可执行文件需要 755 个权限（rwxr-xr-x）。

在 Linux 和 MacOS 中，使用 `chmod` 命令更改部署包中文件和目录的文件权限。例如，要为不可执行文件提供正确的权限，请运行以下命令。

```
chmod 644 <filepath>
```

要在 Windows 中更改文件权限，请参阅 Microsoft Windows 文档中的 [Set, View, Change, or Remove Permissions on an Object](https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2008-R2-and-2008/cc731667(v=ws.10))。

**注意**  
如果您不向 Lambda 授予访问部署包中目录所需的权限，Lambda 会将这些目录的权限设置为 755（rwxr-xr-x）。

### 使用控制台通过 .zip 文件创建和更新函数
<a name="nodejs-package-create-console"></a>

 要创建新函数，必须先在控制台中创建该函数，然后上传您的 .zip 归档。要更新现有函数，请打开函数页面，然后按照相同的步骤添加更新的 .zip 文件。

 如果您的 .zip 文件小于 50MB，则可以通过直接从本地计算机上传该文件来创建或更新函数。对于大于 50MB 的 .zip 文件，必须首先将您的程序包上传到 Amazon S3 存储桶。有关如何使用 Amazon Web Services 管理控制台 将文件上传到 Amazon S3 存储桶的说明，请参阅 [Amazon S3 入门](https://docs.amazonaws.cn/AmazonS3/latest/userguide/GetStartedWithS3.html)。要使用 Amazon CLI 上传文件，请参阅《Amazon CLI 用户指南**》中的[移动对象](https://docs.amazonaws.cn/cli/latest/userguide/cli-services-s3-commands.html#using-s3-commands-managing-objects-move)。

**注意**  
您无法更改现有函数的[部署包类型](https://docs.amazonaws.cn/lambda/latest/api/API_CreateFunction.html#lambda-CreateFunction-request-PackageType)（.zip 或容器映像）。例如，您无法将容器映像函数转换为使用 .zip 文件归档。您必须创建新函数。

**创建新函数（控制台）**

1. 打开 Lambda 控制台的[“函数”页面](https://console.amazonaws.cn/lambda/home#/functions)，然后选择**创建函数**。

1. 选择**从头开始创作**。

1. 在**基本信息**中，执行以下操作：

   1. 对于**函数名称**，输入函数的名称。

   1. 对于**运行时系统**，选择要使用的运行时系统。

   1. （可选）对于**架构**，选择要用于函数的指令集架构。默认架构为 x86\$164。确保您的函数的 .zip 部署包与您选择的指令集架构兼容。

1. （可选）在 **Permissions**（权限）下，展开 **Change default execution role**（更改默认执行角色）。您可以创建新的**执行角色**，也可以使用现有角色。

1. 选择**创建函数**。Lambda 使用您选择的运行时系统创建基本“Hello world”函数。

**从本地计算机上传 .zip 归档（控制台）**

1. 在 Lambda 控制台的[“函数”页面](https://console.amazonaws.cn/lambda/home#/functions)中，选择要为其上传 .zip 文件的函数。

1. 选择**代码**选项卡。

1. 在**代码源**窗格中，选择**上传自**。

1. 选择 **.zip 文件**。

1. 要上传 .zip 文件，请执行以下操作：

   1. 选择**上传**，然后在文件选择器中选择您的 .zip 文件。

   1. 选择**打开**。

   1. 选择**保存**。

**从 Amazon S3 存储桶上传 .zip 归档（控制台）**

1. 在 Lambda 控制台的[“函数”页面](https://console.amazonaws.cn/lambda/home#/functions)中，选择要为其上传新 .zip 文件的函数。

1. 选择**代码**选项卡。

1. 在**代码源**窗格中，选择**上传自**。

1. 选择 **Amazon S3 位置**。

1. 粘贴 .zip 文件的 Amazon S3 链接 URL，然后选择**保存**。

### 使用控制台代码编辑器更新 .zip 文件函数
<a name="nodejs-package-console-edit"></a>

 对于某些带有 .zip 部署包的函数，您可以使用 Lambda 控制台的内置代码编辑器直接更新函数代码。要使用此功能，函数必须满足以下条件：
+ 函数必须使用一种解释性语言运行时系统（Python、Node.js 或 Ruby）
+ 函数的部署包必须小于 50 MB（未压缩状态）。

带有容器映像部署包的函数的代码不能直接在控制台中编辑。

**要使用控制台代码编辑器更新函数代码。**

1. 打开 Lambda 控制台的[“函数”页面](https://console.amazonaws.cn/lambda/home#/functions)，然后选择函数。

1. 选择**代码**选项卡。

1. 在**代码源**窗格中，选择源代码文件并在集成的代码编辑器中对其进行编辑。

1. 在**部署**部分，选择**部署**以更新函数的代码：  
![\[\]](http://docs.amazonaws.cn/lambda/latest/dg/images/getting-started-tutorial/deploy-console.png)

### 使用 Amazon CLI 通过 .zip 文件创建和更新函数
<a name="nodejs-package-create-cli"></a>

 您可以使用 [Amazon CLI](https://docs.amazonaws.cn/cli/latest/userguide/getting-started-install.html) 创建新函数或使用 .zip 文件更新现有函数。使用 [create-function](https://docs.amazonaws.cn/cli/latest/reference/lambda/create-function.html) 和 [update-function-code](https://docs.amazonaws.cn/cli/latest/reference/lambda/create-function.html) 命令部署 .zip 程序包。如果您的 .zip 文件小于 50MB，则可以从本地生成计算机上的文件位置上传 .zip 程序包。对于较大的文件，必须从 Amazon S3 存储桶上传 .zip 程序包。有关如何使用 Amazon CLI 将文件上传到 Amazon S3 存储桶的说明，请参阅《Amazon CLI 用户指南**》中的[移动对象](https://docs.amazonaws.cn/cli/latest/userguide/cli-services-s3-commands.html#using-s3-commands-managing-objects-move)。

**注意**  
如果您使用 Amazon CLI 从 Amazon S3 存储桶上传 .zip 文件，则该存储桶必须与您的函数位于同一个 Amazon Web Services 区域 中。

 要通过 Amazon CLI 使用 .zip 文件创建新函数，则必须指定以下内容：
+ 函数的名称 (`--function-name`)
+ 函数的运行时系统 (`--runtime`)
+ 函数的[执行角色](https://docs.amazonaws.cn/lambda/latest/dg/lambda-intro-execution-role.html) (`--role`) 的 Amazon 资源名称（ARN）
+ 函数代码 (`--handler`) 中处理程序方法的名称

 还必须指定 .zip 文件的位置。如果 .zip 文件位于本地生成计算机上的文件夹中，请使用 `--zip-file` 选项指定文件路径，如以下示例命令所示。

```
aws lambda create-function --function-name myFunction \
--runtime nodejs24.x --handler index.handler \
--role arn:aws:iam::111122223333:role/service-role/my-lambda-role \
--zip-file fileb://myFunction.zip
```

 要指定 .zip 文件在 Amazon S3 存储桶中的位置，请使用 `--code` 选项，如以下示例命令所示。您只需对版本控制对象使用 `S3ObjectVersion` 参数。

```
aws lambda create-function --function-name myFunction \
--runtime nodejs24.x --handler index.handler \
--role arn:aws:iam::111122223333:role/service-role/my-lambda-role \
--code S3Bucket=amzn-s3-demo-bucket,S3Key=myFileName.zip,S3ObjectVersion=myObjectVersion
```

 要使用 CLI 更新现有函数，请使用 `--function-name` 参数指定函数的名称。您还必须指定要用于更新函数代码的 .zip 文件的位置。如果 .zip 文件位于本地生成计算机上的文件夹中，请使用 `--zip-file` 选项指定文件路径，如以下示例命令所示。

```
aws lambda update-function-code --function-name myFunction \
--zip-file fileb://myFunction.zip
```

 要指定 .zip 文件在 Amazon S3 存储桶中的位置，请使用 `--s3-bucket` 和 `--s3-key` 选项，如以下示例命令所示。您只需对版本控制对象使用 `--s3-object-version` 参数。

```
aws lambda update-function-code --function-name myFunction \
--s3-bucket amzn-s3-demo-bucket --s3-key myFileName.zip --s3-object-version myObject Version
```

### 使用 Lambda API 通过 .zip 文件创建和更新函数
<a name="nodejs-package-create-api"></a>

 要使用 .zip 文件归档创建和更新函数，请使用以下 API 操作：
+ [CreateFunction](https://docs.amazonaws.cn/lambda/latest/api/API_CreateFunction.html)
+ [UpdateFunctionCode](https://docs.amazonaws.cn/lambda/latest/api/API_UpdateFunctionCode.html)

### 使用 Amazon SAM 通过 .zip 文件创建和更新函数
<a name="nodejs-package-create-sam"></a>

 Amazon Serverless Application Model（Amazon SAM）是一个工具包，可帮助简化在 Amazon 上构建和运行无服务器应用程序的过程。您可以在 YAML 或 JSON 模板中为应用程序定义资源，并使用 Amazon SAM 命令行界面（Amazon SAM CLI）构建、打包和部署应用程序。当您通过 Amazon SAM 模板构建 Lambda 函数时，Amazon SAM 会使用您的函数代码和您指定的任何依赖项自动创建 .zip 部署包或容器映像。要了解有关使用 Amazon SAM 构建和部署 Lambda 函数的更多信息，请参阅《Amazon Serverless Application Model 开发人员指南**》中的 [Amazon SAM 入门](https://docs.amazonaws.cn/serverless-application-model/latest/developerguide/serverless-getting-started.html)。

您可以使用 Amazon SAM 创建使用现有 .zip 文件归档的 Lambda 函数。要使用 Amazon SAM 创建 Lambda 函数，您可以将 .zip 文件保存在 Amazon S3 存储桶或生成计算机上的本地文件夹中。有关如何使用 Amazon CLI 将文件上传到 Amazon S3 存储桶的说明，请参阅《Amazon CLI 用户指南**》中的[移动对象](https://docs.amazonaws.cn/cli/latest/userguide/cli-services-s3-commands.html#using-s3-commands-managing-objects-move)。

 在 Amazon SAM 模板中，`AWS::Serverless::Function` 资源将指定 Lambda 函数。在此资源中，设置以下属性以创建使用 .zip 文件归档的函数：
+ `PackageType` – 设置为 `Zip`
+ `CodeUri` – 设置为函数代码的 Amazon S3 URI、本地文件夹的路径或 [FunctionCode](https://docs.amazonaws.cn/serverless-application-model/latest/developerguide/sam-property-function-functioncode.html) 对象
+ `Runtime` – 设置为您选择的运行时系统

 使用 Amazon SAM，如果 .zip 文件大于 50MB，则不需要先将其上传到 Amazon S3 存储桶。Amazon SAM 可以从本地生成计算机上的某个位置上传最大允许大小为 250MB（已解压缩）的 .zip 程序包。

 要了解有关在 Amazon SAM 中使用 .zip 文件部署函数的更多信息，请参阅《Amazon SAM 开发人员指南**》中的 [AWS::Serverless::Function](https://docs.amazonaws.cn/serverless-application-model/latest/developerguide/sam-resource-function.html)。

### 使用 Amazon CloudFormation 通过 .zip 文件创建和更新函数
<a name="nodejs-package-create-cfn"></a>

 您可以使用 Amazon CloudFormation 创建使用 .zip 文件归档的 Lambda 函数。要从 .zip 文件创建 Lambda 函数，必须先将您的文件上传到 Amazon S3 存储桶。有关如何使用 Amazon CLI 将文件上传到 Amazon S3 存储桶的说明，请参阅《Amazon CLI 用户指南**》中的[移动对象](https://docs.amazonaws.cn/cli/latest/userguide/cli-services-s3-commands.html#using-s3-commands-managing-objects-move)。

在 Amazon CloudFormation 模板中，`AWS::Lambda::Function` 资源将指定 Lambda 函数。在此资源中，设置以下属性以创建使用 .zip 文件归档的函数：
+ `PackageType` – 设置为 `Zip`
+ `Code` – 在 `S3Bucket` 和 `S3Key` 字段中输入 Amazon S3 存储桶名称和 .zip 文件名。
+ `Runtime` – 设置为您选择的运行时系统

 Amazon CloudFormation 生成的 .zip 文件不能超过 4MB。要了解有关在 Amazon CloudFormation 中使用 .zip 文件部署函数的更多信息，请参阅《Amazon CloudFormation 用户指南**》中的 [AWS::Lambda::Function](https://docs.amazonaws.cn/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-function.html)。

# 使用容器映像部署 Node.js Lambda 函数
<a name="nodejs-image"></a>

有三种方法可以为 Node.js Lambda 函数构建容器映像：
+ [使用 Node.js 的 Amazon 基本映像](#nodejs-image-instructions)

  [Amazon 基本映像](images-create.md#runtimes-images-lp)会预加载一个语言运行时系统、一个用于管理 Lambda 和函数代码之间交互的运行时系统接口客户端，以及一个用于本地测试的运行时系统接口仿真器。
+ [使用 Amazon 仅限操作系统的基础镜像](images-create.md#runtimes-images-provided)

  [Amazon 仅限操作系统的运行时系统](https://gallery.ecr.aws/lambda/provided)包含 Amazon Linux 发行版和[运行时系统接口模拟器](https://github.com/aws/aws-lambda-runtime-interface-emulator/)。这些镜像通常用于为编译语言（例如 [Go](go-image.md#go-image-provided) 和 [Rust](lambda-rust.md)）以及 Lambda 未提供基础映像的语言或语言版本（例如 Node.js 19）创建容器镜像。您也可以使用仅限操作系统的基础映像来实施[自定义运行时系统](runtimes-custom.md)。要使映像与 Lambda 兼容，您必须在映像中包含 [Node.js 的运行时系统接口客户端](#nodejs-image-clients)。
+ [使用非 Amazon 基本映像](#nodejs-image-clients)

  您还可以使用其他容器注册表的备用基本映像，例如 Alpine Linux 或 Debian。您还可以使用您的组织创建的自定义映像。要使映像与 Lambda 兼容，您必须在映像中包含 [Node.js 的运行时系统接口客户端](#nodejs-image-clients)。

**提示**  
要缩短 Lambda 容器函数激活所需的时间，请参阅 Docker 文档中的[使用多阶段构建](https://docs.docker.com/build/building/multi-stage/)。要构建高效的容器映像，请遵循[编写 Dockerfiles 的最佳实践](https://docs.docker.com/develop/develop-images/dockerfile_best-practices/)。

此页面介绍了如何为 Lambda 构建、测试和部署容器映像。

**Topics**
+ [

## Node.js 的 Amazon 基本映像
](#nodejs-image-base)
+ [

## 使用 Node.js 的 Amazon 基本映像
](#nodejs-image-instructions)
+ [

## 将备用基本映像与运行时系统接口客户端配合使用
](#nodejs-image-clients)

## Node.js 的 Amazon 基本映像
<a name="nodejs-image-base"></a>

Amazon 为 Node.js 提供了以下基本映像：


| 标签 | 运行时 | 操作系统 | Dockerfile | 弃用 | 
| --- | --- | --- | --- | --- | 
| 24 | Node.js 24 | Amazon Linux 2023 | [GitHub 上适用于 Node.js 24 的 Dockerfile](https://github.com/aws/aws-lambda-base-images/blob/nodejs24.x/Dockerfile.nodejs24.x) |   2028 年 4 月 30 日   | 
| 22 | Node.js 22 | Amazon Linux 2023 | [GitHub 上适用于 Node.js 22 的 Dockerfile](https://github.com/aws/aws-lambda-base-images/blob/nodejs22.x/Dockerfile.nodejs22.x) |   2027 年 4 月 30 日   | 
| 20 | Node.js 20 | Amazon Linux 2023 | [GitHub 上适用于 Node.js 20 的 Dockerfile](https://github.com/aws/aws-lambda-base-images/blob/nodejs20.x/Dockerfile.nodejs20.x) |   2026 年 4 月 30 日   | 

Amazon ECR 存储库：[gallery.ecr.aws/lambda/nodejs](https://gallery.ecr.aws/lambda/nodejs)

Node.js 20 及更高版本的基础映像基于 [Amazon Linux 2023 最小容器映像](https://docs.amazonaws.cn/linux/al2023/ug/minimal-container.html)。早期的基础映像使用 Amazon Linux 2。与 Amazon Linux 2 相比，AL2023 具有多项优势，包括较小的部署占用空间以及 `glibc` 等更新版本的库。

基于 AL2023 的映像使用 `microdnf`（符号链接为 `dnf`）作为软件包管理器，而不是 Amazon Linux 2 中的默认软件包管理器 `yum`。`microdnf` 是 `dnf` 的独立实现。有关基于 AL2023 的映像中已包含软件包的列表，请参阅[比较 Amazon Linux 2023 容器映像上安装的软件包](https://docs.amazonaws.cn/linux/al2023/ug/al2023-container-image-types.html)中的**最小容器**列。有关 AL2023 和 Amazon Linux 2 之间区别的更多信息，请参阅 Amazon Compute Blog 上的 [Introducing the Amazon Linux 2023 runtime for Amazon Lambda](https://www.amazonaws.cn/blogs/compute/introducing-the-amazon-linux-2023-runtime-for-aws-lambda/)。

**注意**  
要在本地运行基于 AL2023 的映像，包括使用 Amazon Serverless Application Model（Amazon SAM），您必须使用 Docker 版本 20.10.10 或更高版本。

## 使用 Node.js 的 Amazon 基本映像
<a name="nodejs-image-instructions"></a>

### 先决条件
<a name="nodejs-image-prerequisites"></a>

要完成本节中的步骤，您必须满足以下条件：
+ [Amazon CLI 版本 2](https://docs.amazonaws.cn/cli/latest/userguide/getting-started-install.html)
+ [Docker](https://docs.docker.com/get-docker)（最低版本 25.0.0）
+ Docker [buildx 插件](https://github.com/docker/buildx/blob/master/README.md)。
+ Node.js

### 从基本映像创建映像
<a name="nodejs-image-create"></a>

**从 Node.js 的 Amazon 的基本映像创建容器映像**

1. 为项目创建一个目录，然后切换到该目录。

   ```
   mkdir example
   cd example
   ```

1. 使用 `npm` 创建新的 Node.js 项目。要在交互式体验中接受提供的默认选项，请按 `Enter`。

   ```
   npm init
   ```

1. 创建名为 `index.js` 的新文件。您可以将以下示例函数代码添加到文件中进行测试，也可以使用您自己的函数代码。  
**Example CommonJS 处理程序**  

   ```
   exports.handler = async (event) => {
       const response = {
           statusCode: 200,
           body: JSON.stringify('Hello from Lambda!'),
       };
       return response;
   };
   ```

1. 如果函数依赖于 适用于 JavaScript 的 Amazon SDK 之外的库，请使用 [npm](https://www.npmjs.com/) 将其添加到程序包。

1. 使用以下配置创建一个新的 Dockerfile。
   + 将 `FROM` 属性设置为[基本映像的 URI](https://gallery.ecr.aws/lambda/nodejs)。
   + 使用 COPY 命令将函数代码和运行时系统依赖项复制到 `{LAMBDA_TASK_ROOT}`，此为 [Lambda 定义的环境变量](configuration-envvars.md#configuration-envvars-runtime)。
   + 将 `CMD` 参数设置为 Lambda 函数处理程序。

   请注意，示例 Dockerfile 不包含 [USER 指令](https://docs.docker.com/reference/dockerfile/#user)。当您将容器映像部署到 Lambda 时，Lambda 会自动定义具有最低权限的默认 Linux 用户。这与标准 Docker 行为不同，标准 Docker 在未提供 `USER` 指令时默认为 `root` 用户。  
**Example Dockerfile**  

   ```
   FROM public.ecr.aws/lambda/nodejs:22
   
   # Copy function code
   COPY index.js ${LAMBDA_TASK_ROOT}
     
   # Set the CMD to your handler (could also be done as a parameter override outside of the Dockerfile)
   CMD [ "index.handler" ]
   ```

1. 使用 [docker build](https://docs.docker.com/engine/reference/commandline/build/) 命令构建 Docker 映像。以下示例将映像命名为 `docker-image` 并为其提供 `test` [标签](https://docs.docker.com/engine/reference/commandline/build/#tag)。要使您的映像与 Lambda 兼容，您必须使用 `--provenance=false` 选项。

   ```
   docker buildx build --platform linux/amd64 --provenance=false -t docker-image:test .
   ```
**注意**  
该命令指定了 `--platform linux/amd64` 选项，可确保无论生成计算机的架构如何，容器始终与 Lambda 执行环境兼容。如果打算使用 ARM64 指令集架构创建 Lambda 函数，请务必将命令更改为使用 `--platform linux/arm64` 选项。

### （可选）在本地测试映像
<a name="nodejs-image-test"></a>

1. 使用 **docker run** 命令启动 Docker 映像。在此示例中，`docker-image` 是映像名称，`test` 是标签。

   ```
   docker run --platform linux/amd64 -p 9000:8080 docker-image:test
   ```

   此命令会将映像作为容器运行，并在 `localhost:9000/2015-03-31/functions/function/invocations` 创建本地端点。
**注意**  
如果为 ARM64 指令集架构创建 Docker 映像，请务必使用 `--platform linux/arm64` 选项，而不是 `--platform linux/amd64` 选项。

1. 在新的终端窗口中，将事件发布到本地端点。

------
#### [ Linux/macOS ]

   在 Linux 和 macOS 中，运行以下 `curl` 命令：

   ```
   curl "http://localhost:9000/2015-03-31/functions/function/invocations" -d '{}'
   ```

   此命令使用空事件调用函数并返回响应。如果您使用自己的函数代码而不是示例函数代码，则可能需要使用 JSON 负载调用函数。示例：

   ```
   curl "http://localhost:9000/2015-03-31/functions/function/invocations" -d '{"payload":"hello world!"}'
   ```

------
#### [ PowerShell ]

   在 PowerShell 中，运行以下 `Invoke-WebRequest` 命令：

   ```
   Invoke-WebRequest -Uri "http://localhost:9000/2015-03-31/functions/function/invocations" -Method Post -Body '{}' -ContentType "application/json"
   ```

   此命令使用空事件调用函数并返回响应。如果您使用自己的函数代码而不是示例函数代码，则可能需要使用 JSON 负载调用函数。示例：

   ```
   Invoke-WebRequest -Uri "http://localhost:9000/2015-03-31/functions/function/invocations" -Method Post -Body '{"payload":"hello world!"}' -ContentType "application/json"
   ```

------

1. 获取容器 ID。

   ```
   docker ps
   ```

1. 使用 [docker kill](https://docs.docker.com/engine/reference/commandline/kill/) 命令停止容器。在此命令中，将 `3766c4ab331c` 替换为上一步中的容器 ID。

   ```
   docker kill 3766c4ab331c
   ```

### 部署映像
<a name="nodejs-image-deploy"></a>

**将映像上传到 Amazon ECR 并创建 Lambda 函数**

1. 运行 [get-login-password](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ecr/get-login-password.html) 命令，以针对 Amazon ECR 注册表进行 Docker CLI 身份验证。
   + 将 `--region` 值设置为要在其中创建 Amazon ECR 存储库的 Amazon Web Services 区域。
   + 将 `111122223333` 替换为您的 Amazon Web Services 账户 ID。

   ```
   aws ecr get-login-password --region cn-north-1 | docker login --username AWS --password-stdin 111122223333.dkr.ecr.cn-north-1.amazonaws.com.cn
   ```

1. 使用 [create-repository](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ecr/create-repository.html) 命令在 Amazon ECR 中创建存储库。

   ```
   aws ecr create-repository --repository-name hello-world --region cn-north-1 --image-scanning-configuration scanOnPush=true --image-tag-mutability MUTABLE
   ```
**注意**  
Amazon ECR 存储库必须与 Lambda 函数位于同一 Amazon Web Services 区域 内。

   如果成功，您将会看到如下响应：

   ```
   {
       "repository": {
           "repositoryArn": "arn:aws:ecr:cn-north-1:111122223333:repository/hello-world",
           "registryId": "111122223333",
           "repositoryName": "hello-world",
           "repositoryUri": "111122223333.dkr.ecr.cn-north-1.amazonaws.com.cn/hello-world",
           "createdAt": "2023-03-09T10:39:01+00:00",
           "imageTagMutability": "MUTABLE",
           "imageScanningConfiguration": {
               "scanOnPush": true
           },
           "encryptionConfiguration": {
               "encryptionType": "AES256"
           }
       }
   }
   ```

1. 从上一步的输出中复制 `repositoryUri`。

1. 运行 [docker tag](https://docs.docker.com/engine/reference/commandline/tag/) 命令，将本地映像作为最新版本标记到 Amazon ECR 存储库中。在此命令中：
   + `docker-image:test` 是 Docker 映像的名称和[标签](https://docs.docker.com/engine/reference/commandline/build/#tag)。这是您在 `docker build` 命令中指定的映像名称和标签。
   + 将 `<ECRrepositoryUri>` 替换为复制的 `repositoryUri`。确保 URI 末尾包含 `:latest`。

   ```
   docker tag docker-image:test <ECRrepositoryUri>:latest
   ```

   示例：

   ```
   docker tag docker-image:test 111122223333.dkr.ecr.cn-north-1.amazonaws.com.cn/hello-world:latest
   ```

1. 运行 [docker push](https://docs.docker.com/engine/reference/commandline/push/) 命令，以将本地映像部署到 Amazon ECR 存储库。确保存储库 URI 末尾包含 `:latest`。

   ```
   docker push 111122223333.dkr.ecr.cn-north-1.amazonaws.com.cn/hello-world:latest
   ```

1. 如果您还没有函数的执行角色，请[创建执行角色](lambda-intro-execution-role.md#permissions-executionrole-api)。在下一步中，您需要提供角色的 Amazon 资源名称（ARN）。

1. 创建 Lambda 函数。对于 `ImageUri`，指定之前的存储库 URI。确保 URI 末尾包含 `:latest`。

   ```
   aws lambda create-function \
     --function-name hello-world \
     --package-type Image \
     --code ImageUri=111122223333.dkr.ecr.cn-north-1.amazonaws.com.cn/hello-world:latest \
     --role arn:aws:iam::111122223333:role/lambda-ex
   ```
**注意**  
只要映像与 Lambda 函数位于同一区域内，您就可以使用其他 Amazon 账户中的映像创建函数。有关更多信息，请参阅 [Amazon ECR 跨账户权限](images-create.md#configuration-images-xaccount-permissions)。

1. 调用函数。

   ```
   aws lambda invoke --function-name hello-world response.json
   ```

   应出现如下响应：

   ```
   {
     "ExecutedVersion": "$LATEST", 
     "StatusCode": 200
   }
   ```

1. 要查看函数的输出，请检查 `response.json` 文件。

要更新函数代码，您必须再次构建映像，将新映像上传到 Amazon ECR 存储库，然后使用 [update-function-code](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/update-function-code.html) 命令将映像部署到 Lambda 函数。

Lambda 会将映像标签解析为特定的映像摘要。这意味着，如果您将用于部署函数的映像标签指向 Amazon ECR 中的新映像，则 Lambda 不会自动更新该函数以使用新映像。

要将新映像部署到相同的 Lambda 函数，即使 Amazon ECR 中的映像标签保持不变，也必须使用 [update-function-code](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/update-function-code.html) 命令。在以下示例中，`--publish` 选项使用更新的容器映像创建函数的新版本。

```
aws lambda update-function-code \
  --function-name hello-world \
  --image-uri 111122223333.dkr.ecr.cn-north-1.amazonaws.com.cn/hello-world:latest \
  --publish
```

## 将备用基本映像与运行时系统接口客户端配合使用
<a name="nodejs-image-clients"></a>

如果使用[仅限操作系统的基础映像](images-create.md#runtimes-images-provided)或者备用基础映像，则必须在映像中包括运行时系统接口客户端。运行时系统接口客户端可扩展 [运行时 API](runtimes-api.md)，用于管理 Lambda 和函数代码之间的交互。

使用 npm 包管理器安装 [Node.js 运行时系统接口客户端](https://www.npmjs.com/package/aws-lambda-ric)：

```
npm install aws-lambda-ric
```

您也可以从 GitHub 下载 [Node.js 运行时接口客户端](https://github.com/aws/aws-lambda-nodejs-runtime-interface-client)。

以下示例演示了如何使用非 Amazon 基本映像为 Node.js 构建容器映像。示例 Dockerfile 使用 `bookworm` 基本映像。Docker 包含运行时系统接口客户端。

### 先决条件
<a name="nodejs-alt-prerequisites"></a>

要完成本节中的步骤，您必须满足以下条件：
+ [Amazon CLI 版本 2](https://docs.amazonaws.cn/cli/latest/userguide/getting-started-install.html)
+ [Docker](https://docs.docker.com/get-docker)（最低版本 25.0.0）
+ Docker [buildx 插件](https://github.com/docker/buildx/blob/master/README.md)。
+ Node.js

### 从备用基本映像创建映像
<a name="nodejs-alt-create"></a>

**要从非 Amazon 基本映像创建容器映像**

1. 为项目创建一个目录，然后切换到该目录。

   ```
   mkdir example
   cd example
   ```

1. 使用 `npm` 创建新的 Node.js 项目。要在交互式体验中接受提供的默认选项，请按 `Enter`。

   ```
   npm init
   ```

1. 创建名为 `index.js` 的新文件。您可以将以下示例函数代码添加到文件中进行测试，也可以使用您自己的函数代码。  
**Example CommonJS 处理程序**  

   ```
   exports.handler = async (event) => {
       const response = {
           statusCode: 200,
           body: JSON.stringify('Hello from Lambda!'),
       };
       return response;
   };
   ```

1. 创建新 Dockerfile。以下 Dockerfile 使用 `bookworm` 基本映像而不是 [Amazon 基本映像](images-create.md#runtimes-images-lp)。Dockerfile 包含[运行时系统接口客户端](https://www.npmjs.com/package/aws-lambda-ric)，该客户端可使映像与 Lambda 兼容。Dockerfile 使用[多阶段构建](https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#use-multi-stage-builds)。第一阶段将创建一个构建映像，作为安装函数依赖项的标准 Node.js 环境。第二阶段创建一个更精简的映像，其中包含函数代码及其依赖项。此机制可缩减最终映像大小。
   + 将 `FROM` 属性设置为基本映像标识符。
   + 使用 `COPY` 命令将复制函数代码和运行时系统依赖项。
   + 将 `ENTRYPOINT` 设置为您希望 Docker 容器在启动时运行的模块。在本例中，模块为运行时系统接口客户端。
   + 将 `CMD` 参数设置为 Lambda 函数处理程序。

   请注意，示例 Dockerfile 不包含 [USER 指令](https://docs.docker.com/reference/dockerfile/#user)。当您将容器映像部署到 Lambda 时，Lambda 会自动定义具有最低权限的默认 Linux 用户。这与标准 Docker 行为不同，标准 Docker 在未提供 `USER` 指令时默认为 `root` 用户。  
**Example Dockerfile**  

   ```
   # Define custom function directory
   ARG FUNCTION_DIR="/function"
   
   FROM node:20-bookworm as build-image
   
   # Include global arg in this stage of the build
   ARG FUNCTION_DIR
   
   # Install build dependencies
   RUN apt-get update && \
       apt-get install -y \
       g++ \
       make \
       cmake \
       unzip \
       libcurl4-openssl-dev
   
   # Copy function code
   RUN mkdir -p ${FUNCTION_DIR}
   COPY . ${FUNCTION_DIR}
   
   WORKDIR ${FUNCTION_DIR}
   
   # Install Node.js dependencies
   RUN npm install
   
   # Install the runtime interface client
   RUN npm install aws-lambda-ric
   
   # Grab a fresh slim copy of the image to reduce the final size
   FROM node:20-bookworm-slim
   
   # Required for Node runtimes which use npm@8.6.0+ because
   # by default npm writes logs under /home/.npm and Lambda fs is read-only
   ENV NPM_CONFIG_CACHE=/tmp/.npm
   
   # Include global arg in this stage of the build
   ARG FUNCTION_DIR
   
   # Set working directory to function root directory
   WORKDIR ${FUNCTION_DIR}
   
   # Copy in the built dependencies
   COPY --from=build-image ${FUNCTION_DIR} ${FUNCTION_DIR}
   
   # Set runtime interface client as default command for the container runtime
   ENTRYPOINT ["/usr/local/bin/npx", "aws-lambda-ric"]
   # Pass the name of the function handler as an argument to the runtime
   CMD ["index.handler"]
   ```

1. 使用 [docker build](https://docs.docker.com/engine/reference/commandline/build/) 命令构建 Docker 映像。以下示例将映像命名为 `docker-image` 并为其提供 `test` [标签](https://docs.docker.com/engine/reference/commandline/build/#tag)。要使您的映像与 Lambda 兼容，您必须使用 `--provenance=false` 选项。

   ```
   docker buildx build --platform linux/amd64 --provenance=false -t docker-image:test .
   ```
**注意**  
该命令指定了 `--platform linux/amd64` 选项，可确保无论生成计算机的架构如何，容器始终与 Lambda 执行环境兼容。如果打算使用 ARM64 指令集架构创建 Lambda 函数，请务必将命令更改为使用 `--platform linux/arm64` 选项。

### （可选）在本地测试映像
<a name="nodejs-alt-test"></a>

使用[运行时系统接口仿真器](https://github.com/aws/aws-lambda-runtime-interface-emulator/)在本地测试映像。您可以[将仿真器构建到映像中](https://github.com/aws/aws-lambda-runtime-interface-emulator/?tab=readme-ov-file#build-rie-into-your-base-image)，也可以使用以下程序将其安装在本地计算机上。

**在本地计算机上安装并运行运行时系统接口仿真器**

1. 从项目目录中，运行以下命令以从 GitHub 下载运行时系统接口仿真器（x86-64 架构）并将其安装在本地计算机上。

------
#### [ Linux/macOS ]

   ```
   mkdir -p ~/.aws-lambda-rie && \
       curl -Lo ~/.aws-lambda-rie/aws-lambda-rie https://github.com/aws/aws-lambda-runtime-interface-emulator/releases/latest/download/aws-lambda-rie && \
       chmod +x ~/.aws-lambda-rie/aws-lambda-rie
   ```

   要安装 arm64 仿真器，请将上一条命令中的 GitHub 存储库 URL 替换为以下内容：

   ```
   https://github.com/aws/aws-lambda-runtime-interface-emulator/releases/latest/download/aws-lambda-rie-arm64
   ```

------
#### [ PowerShell ]

   ```
   $dirPath = "$HOME\.aws-lambda-rie"
   if (-not (Test-Path $dirPath)) {
       New-Item -Path $dirPath -ItemType Directory
   }
         
   $downloadLink = "https://github.com/aws/aws-lambda-runtime-interface-emulator/releases/latest/download/aws-lambda-rie"
   $destinationPath = "$HOME\.aws-lambda-rie\aws-lambda-rie"
   Invoke-WebRequest -Uri $downloadLink -OutFile $destinationPath
   ```

   要安装 arm64 模拟器，请将 `$downloadLink` 替换为以下内容：

   ```
   https://github.com/aws/aws-lambda-runtime-interface-emulator/releases/latest/download/aws-lambda-rie-arm64
   ```

------

1. 使用 **docker run** 命令启动 Docker 映像。请注意以下几点：
   + `docker-image` 是映像名称，`test` 是标签。
   + `/usr/local/bin/npx aws-lambda-ric index.handler` 是 `ENTRYPOINT`，后跟您 Dockerfile 中的 `CMD`。

------
#### [ Linux/macOS ]

   ```
   docker run --platform linux/amd64 -d -v ~/.aws-lambda-rie:/aws-lambda -p 9000:8080 \
       --entrypoint /aws-lambda/aws-lambda-rie \
       docker-image:test \
           /usr/local/bin/npx aws-lambda-ric index.handler
   ```

------
#### [ PowerShell ]

   ```
   docker run --platform linux/amd64 -d -v "$HOME\.aws-lambda-rie:/aws-lambda" -p 9000:8080 `
   --entrypoint /aws-lambda/aws-lambda-rie `
   docker-image:test `
       /usr/local/bin/npx aws-lambda-ric index.handler
   ```

------

   此命令会将映像作为容器运行，并在 `localhost:9000/2015-03-31/functions/function/invocations` 创建本地端点。
**注意**  
如果为 ARM64 指令集架构创建 Docker 映像，请务必使用 `--platform linux/arm64` 选项，而不是 `--platform linux/amd64` 选项。

1. 将事件发布到本地端点。

------
#### [ Linux/macOS ]

   在 Linux 和 macOS 中，运行以下 `curl` 命令：

   ```
   curl "http://localhost:9000/2015-03-31/functions/function/invocations" -d '{}'
   ```

   此命令使用空事件调用函数并返回响应。如果您使用自己的函数代码而不是示例函数代码，则可能需要使用 JSON 负载调用函数。示例：

   ```
   curl "http://localhost:9000/2015-03-31/functions/function/invocations" -d '{"payload":"hello world!"}'
   ```

------
#### [ PowerShell ]

   在 PowerShell 中，运行以下 `Invoke-WebRequest` 命令：

   ```
   Invoke-WebRequest -Uri "http://localhost:9000/2015-03-31/functions/function/invocations" -Method Post -Body '{}' -ContentType "application/json"
   ```

   此命令使用空事件调用函数并返回响应。如果您使用自己的函数代码而不是示例函数代码，则可能需要使用 JSON 负载调用函数。示例：

   ```
   Invoke-WebRequest -Uri "http://localhost:9000/2015-03-31/functions/function/invocations" -Method Post -Body '{"payload":"hello world!"}' -ContentType "application/json"
   ```

------

1. 获取容器 ID。

   ```
   docker ps
   ```

1. 使用 [docker kill](https://docs.docker.com/engine/reference/commandline/kill/) 命令停止容器。在此命令中，将 `3766c4ab331c` 替换为上一步中的容器 ID。

   ```
   docker kill 3766c4ab331c
   ```

### 部署映像
<a name="nodejs-alt-deploy"></a>

**将映像上传到 Amazon ECR 并创建 Lambda 函数**

1. 运行 [get-login-password](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ecr/get-login-password.html) 命令，以针对 Amazon ECR 注册表进行 Docker CLI 身份验证。
   + 将 `--region` 值设置为要在其中创建 Amazon ECR 存储库的 Amazon Web Services 区域。
   + 将 `111122223333` 替换为您的 Amazon Web Services 账户 ID。

   ```
   aws ecr get-login-password --region cn-north-1 | docker login --username AWS --password-stdin 111122223333.dkr.ecr.cn-north-1.amazonaws.com.cn
   ```

1. 使用 [create-repository](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ecr/create-repository.html) 命令在 Amazon ECR 中创建存储库。

   ```
   aws ecr create-repository --repository-name hello-world --region cn-north-1 --image-scanning-configuration scanOnPush=true --image-tag-mutability MUTABLE
   ```
**注意**  
Amazon ECR 存储库必须与 Lambda 函数位于同一 Amazon Web Services 区域 内。

   如果成功，您将会看到如下响应：

   ```
   {
       "repository": {
           "repositoryArn": "arn:aws:ecr:cn-north-1:111122223333:repository/hello-world",
           "registryId": "111122223333",
           "repositoryName": "hello-world",
           "repositoryUri": "111122223333.dkr.ecr.cn-north-1.amazonaws.com.cn/hello-world",
           "createdAt": "2023-03-09T10:39:01+00:00",
           "imageTagMutability": "MUTABLE",
           "imageScanningConfiguration": {
               "scanOnPush": true
           },
           "encryptionConfiguration": {
               "encryptionType": "AES256"
           }
       }
   }
   ```

1. 从上一步的输出中复制 `repositoryUri`。

1. 运行 [docker tag](https://docs.docker.com/engine/reference/commandline/tag/) 命令，将本地映像作为最新版本标记到 Amazon ECR 存储库中。在此命令中：
   + `docker-image:test` 是 Docker 映像的名称和[标签](https://docs.docker.com/engine/reference/commandline/build/#tag)。这是您在 `docker build` 命令中指定的映像名称和标签。
   + 将 `<ECRrepositoryUri>` 替换为复制的 `repositoryUri`。确保 URI 末尾包含 `:latest`。

   ```
   docker tag docker-image:test <ECRrepositoryUri>:latest
   ```

   示例：

   ```
   docker tag docker-image:test 111122223333.dkr.ecr.cn-north-1.amazonaws.com.cn/hello-world:latest
   ```

1. 运行 [docker push](https://docs.docker.com/engine/reference/commandline/push/) 命令，以将本地映像部署到 Amazon ECR 存储库。确保存储库 URI 末尾包含 `:latest`。

   ```
   docker push 111122223333.dkr.ecr.cn-north-1.amazonaws.com.cn/hello-world:latest
   ```

1. 如果您还没有函数的执行角色，请[创建执行角色](lambda-intro-execution-role.md#permissions-executionrole-api)。在下一步中，您需要提供角色的 Amazon 资源名称（ARN）。

1. 创建 Lambda 函数。对于 `ImageUri`，指定之前的存储库 URI。确保 URI 末尾包含 `:latest`。

   ```
   aws lambda create-function \
     --function-name hello-world \
     --package-type Image \
     --code ImageUri=111122223333.dkr.ecr.cn-north-1.amazonaws.com.cn/hello-world:latest \
     --role arn:aws:iam::111122223333:role/lambda-ex
   ```
**注意**  
只要映像与 Lambda 函数位于同一区域内，您就可以使用其他 Amazon 账户中的映像创建函数。有关更多信息，请参阅 [Amazon ECR 跨账户权限](images-create.md#configuration-images-xaccount-permissions)。

1. 调用函数。

   ```
   aws lambda invoke --function-name hello-world response.json
   ```

   应出现如下响应：

   ```
   {
     "ExecutedVersion": "$LATEST", 
     "StatusCode": 200
   }
   ```

1. 要查看函数的输出，请检查 `response.json` 文件。

要更新函数代码，您必须再次构建映像，将新映像上传到 Amazon ECR 存储库，然后使用 [update-function-code](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/update-function-code.html) 命令将映像部署到 Lambda 函数。

Lambda 会将映像标签解析为特定的映像摘要。这意味着，如果您将用于部署函数的映像标签指向 Amazon ECR 中的新映像，则 Lambda 不会自动更新该函数以使用新映像。

要将新映像部署到相同的 Lambda 函数，即使 Amazon ECR 中的映像标签保持不变，也必须使用 [update-function-code](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/update-function-code.html) 命令。在以下示例中，`--publish` 选项使用更新的容器映像创建函数的新版本。

```
aws lambda update-function-code \
  --function-name hello-world \
  --image-uri 111122223333.dkr.ecr.cn-north-1.amazonaws.com.cn/hello-world:latest \
  --publish
```

# 使用 Node.js Lambda 函数的层
<a name="nodejs-layers"></a>

使用 [Lambda 层](chapter-layers.md)来打包要在多个函数中重复使用的代码和依赖项。层通常包含库依赖项、[自定义运行时系统](runtimes-custom.md)或配置文件。创建层涉及三个常见步骤：

1. 打包层内容。此步骤需要创建 .zip 文件存档，其中包含要在函数中使用的依赖项。

1. 在 Lambda 中创建层。

1. 将层添加到函数。

**Topics**
+ [

## 打包层内容
](#nodejs-layers-package)
+ [

## 在 Lambda 中创建层
](#publishing-layer)
+ [

## 将层添加到函数
](#nodejs-layer-adding)
+ [

## 示例应用程序
](#nodejs-layer-sample-app)

## 打包层内容
<a name="nodejs-layers-package"></a>

要创建层，请将您的包捆绑到满足以下要求的 .zip 文件存档中：
+ 使用计划用于 Lambda 函数的相同 Node.js 版本来构建层。例如，如果您使用 Node.js 24 来构建层，则您的函数应使用 Node.js 24 运行时。
+ 您层的 .zip 文件必须使用以下目录结构之一：
  + `nodejs/node_modules`
  + `nodejs/nodeX/node_modules`（例如，其中 *X* 是您的 Node.js 版本`node22`）

  有关更多信息，请参阅 [每个 Lambda 运行时的层路径](packaging-layers.md#packaging-layers-paths)。
+ 您的层中的包必须与 Linux 兼容。Lambda 函数在 Amazon Linux 上运行。

您可以创建包含使用 `npm` 安装的第三方 Node.js 库（例如 `axios` 或 `lodash`）或者您自己的 JavaScript 模块。

### 第三方依赖项
<a name="nodejs-layers-third-party-dependencies"></a>

**要使用 npm 包创建层**

1. 创建所需的目录结构，并将包直接安装到其中：

   ```
   mkdir -p nodejs
   npm install --prefix nodejs lodash axios
   ```

   此命令是将包直接安装到 `nodejs/node_modules` 目录中，这是 Lambda 所需的结构。
**注意**  
对于具有原生依赖项或二进制组件（例如，[sharp](https://www.npmjs.com/package/sharp) 或 [bcrypt](https://www.npmjs.com/package/bcrypt)）的包，请确保它们与 Lambda Linux 环境以及您的函数[架构](foundation-arch.md)兼容。您可能需要使用 `--platform` 标志：  

   ```
   npm install --prefix nodejs --platform=linux --arch=x64 sharp
   ```
对于更复杂的原生依赖项，您可能需要在与 Lambda 运行时匹配的 Linux 环境中对其进行编译。您可以使用 Docker 来实现这一目的。

1. 压缩层内容：

------
#### [ Linux/macOS ]

   ```
   zip -r layer.zip nodejs/
   ```

------
#### [ PowerShell ]

   ```
   Compress-Archive -Path .\nodejs -DestinationPath .\layer.zip
   ```

------

   您的 .zip 文件的目录结构应如下所示：

   ```
   nodejs/
   ├── package.json
   ├── package-lock.json
   └── node_modules/
       ├── lodash/
       ├── axios/
       └── (dependencies of the other packages)
   ```
**注意**  
请确保您的 .zip 文件包含位于根级别下的 `nodejs` 目录，且该目录内包含 `node_modules`。此结构旨在确保 Lambda 可以找到并导入您的包。
`nodejs/` 目录中的 `package.json` 和 `package-lock.json` 文件供 npm 用于依赖项管理，但 Lambda 不需要使用这些文件来实现层功能。每个已安装的软件包中已经包含自己的 `package.json` 文件，其中定义了 Lambda 如何导入软件包。

### 自定义 JavaScript 模块
<a name="custom-nodejs-modules"></a>

**使用您自己的代码创建层**

1. 为您的层创建所需的目录结构：

   ```
   mkdir -p nodejs/node_modules/validator
   cd nodejs/node_modules/validator
   ```

1. 为您的自定义模块创建一个 `package.json` 文件，以定义其导入方式：  
**Example nodejs/node\$1modules/validator/package.json**  

   ```
   {
     "name": "validator",
     "version": "1.0.0",
     "type": "module",
     "main": "index.mjs"
   }
   ```

1. 创建您的 JavaScript 模块文件：  
**Example nodejs/node\$1modules/validator/index.mjs**  

   ```
   export function validateOrder(orderData) {
     // Validates an order and returns formatted data
     const requiredFields = ['productId', 'quantity'];
     
     // Check required fields
     const missingFields = requiredFields.filter(field => !(field in orderData));
     if (missingFields.length > 0) {
       throw new Error(`Missing required fields: ${missingFields.join(', ')}`);
     }
     
     // Validate quantity
     const quantity = orderData.quantity;
     if (!Number.isInteger(quantity) || quantity < 1) {
       throw new Error('Quantity must be a positive integer');
     }
     
     // Format and return the validated data
     return {
       productId: String(orderData.productId),
       quantity: quantity,
       shippingPriority: orderData.priority || 'standard'
     };
   }
   
   export function formatResponse(statusCode, body) {
     // Formats the API response
     return {
       statusCode: statusCode,
       body: JSON.stringify(body)
     };
   }
   ```

1. 压缩层内容：

------
#### [ Linux/macOS ]

   ```
   zip -r layer.zip nodejs/
   ```

------
#### [ PowerShell ]

   ```
   Compress-Archive -Path .\nodejs -DestinationPath .\layer.zip
   ```

------

   您的 .zip 文件的目录结构应如下所示：

   ```
   nodejs/              
   └── node_modules/
       └── validator/
           ├── package.json
           └── index.mjs
   ```

1. 在您的函数中导入并使用这些模块。示例：

   ```
   import { validateOrder, formatResponse } from 'validator';
   
   export const handler = async (event) => {
     try {
       // Parse the order data from the event body
       const orderData = JSON.parse(event.body || '{}');
       
       // Validate and format the order
       const validatedOrder = validateOrder(orderData);
       
       return formatResponse(200, {
         message: 'Order validated successfully',
         order: validatedOrder
       });
     } catch (error) {
       if (error instanceof Error && error.message.includes('Missing required fields')) {
         return formatResponse(400, {
           error: error.message
         });
       }
       
       return formatResponse(500, {
         error: 'Internal server error'
       });
     }
   };
   ```

   您可以使用以下[测试事件](testing-functions.md#invoke-with-event)调用函数：

   ```
   {
       "body": "{\"productId\": \"ABC123\", \"quantity\": 2, \"priority\": \"express\"}"
   }
   ```

   预期的回应：

   ```
   {
     "statusCode": 200,
     "body": "{\"message\":\"Order validated successfully\",\"order\":{\"productId\":\"ABC123\",\"quantity\":2,\"shippingPriority\":\"express\"}}"
   }
   ```

## 在 Lambda 中创建层
<a name="publishing-layer"></a>

您可以使用 Amazon CLI 或 Lambda 控制台发布层。

------
#### [ Amazon CLI ]

运行 [publish-layer-version](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/publish-layer-version.html) Amazon CLI 命令以创建 Lambda 层：

```
aws lambda publish-layer-version --layer-name my-layer --zip-file fileb://layer.zip --compatible-runtimes nodejs24.x
```

[兼容的运行时](https://docs.amazonaws.cn/lambda/latest/api/API_PublishLayerVersion.html#lambda-PublishLayerVersion-request-CompatibleRuntimes)参数是可选的。指定后，Lambda 将使用此参数在 Lambda 控制台中筛选层。

------
#### [ Console ]

**创建层（控制台）**

1. 打开 Lambda 控制台的 [Layers page](https://console.amazonaws.cn/lambda/home#/layers)（层页面）。

1. 选择 **Create layer**（创建层）。

1. 选择**上传 .zip 文件**，然后上传您之前创建的 .zip 存档。

1. （可选）对于**兼容的运行时**，请选择与您用于构建层的 Node.js 版本相对应的 Node.js 运行时。

1. 选择**创建**。

------

## 将层添加到函数
<a name="nodejs-layer-adding"></a>

------
#### [ Amazon CLI ]

要将层附加到函数，请运行 [update-function-configuration](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/update-function-configuration.html) Amazon CLI 命令。对于 `--layers` 参数，使用层 ARN。ARN 必须指定版本（例如 `arn:aws:lambda:us-east-1:123456789012:layer:my-layer:1`）。有关更多信息，请参阅 [层和层版本](chapter-layers.md#lambda-layer-versions)。

```
aws lambda update-function-configuration --function-name my-function --cli-binary-format raw-in-base64-out --layers "arn:aws:lambda:us-east-1:123456789012:layer:my-layer:1"
```

如果使用 **cli-binary-format** 版本 2，则 Amazon CLI 选项是必需的。要将其设为默认设置，请运行 `aws configure set cli-binary-format raw-in-base64-out`。有关更多信息，请参阅*版本 2 的 Amazon Command Line Interface 用户指南*中的 [Amazon CLI 支持的全局命令行选项](https://docs.amazonaws.cn/cli/latest/userguide/cli-configure-options.html#cli-configure-options-list)。

------
#### [ Console ]

**向函数添加层**

1. 打开 Lamba 控制台的[函数](https://console.amazonaws.cn/lambda/home#/functions)页面。

1. 选择函数。

1. 向下滚动到**层**部分，然后选择**添加层**。

1. 在**选择层**下，选择**自定义层**，然后选择您的层。
**注意**  
如果您在创建层时没有添加[兼容的运行时](https://docs.amazonaws.cn/lambda/latest/api/API_PublishLayerVersion.html#lambda-PublishLayerVersion-request-CompatibleRuntimes)，则您的层将不会在此处列出。您可以改为指定层 ARN。

1. 选择**添加**。

------

## 示例应用程序
<a name="nodejs-layer-sample-app"></a>

有关如何使用 Lambda 层的更多示例，请参阅 Amazon Lambda Developer Guide GitHub 存储库中的 [layer-nodejs](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/layer-nodejs) 示例应用程序。此应用程序中有一个包含 [lodash](https://www.npmjs.com/package/lodash) 库的层。创建层后，即可部署并调用相应的函数来确认层是否按预期运行。

# 使用 Lambda 上下文对象检索 Node.js 函数信息
<a name="nodejs-context"></a>

当 Lambda 运行您的函数时，它会将上下文对象传递到[处理程序](nodejs-handler.md)。此对象提供的方法和属性包含有关调用、函数和执行环境的信息。

**上下文方法**
+ `getRemainingTimeInMillis()` – 返回执行超时前剩余的毫秒数。

**上下文属性**
+ `functionName` – Lambda 函数的名称。
+ `functionVersion` – 函数的[版本](configuration-versions.md)
+ `invokedFunctionArn` – 用于调用函数的 Amazon Resource Name (ARN)。表明调用者是否指定了版本号或别名。
+ `memoryLimitInMB` – 为函数分配的内存量。
+ `awsRequestId` – 调用请求的标识符。
+ `logGroupName` – 函数的日志组。
+ `logStreamName` – 函数实例的日志流。
+ `identity` –（移动应用程序）有关授权请求的 Amazon Cognito 身份的信息。
  + `cognitoIdentityId` – 经过身份验证的 Amazon Cognito 身份。
  + `cognitoIdentityPoolId` – 授权调用的 Amazon Cognito 身份池。
+ `clientContext` –（移动应用程序）客户端应用程序提供给 Lambda 的客户端上下文。
  + `client.installation_id`
  + `client.app_title`
  + `client.app_version_name`
  + `client.app_version_code`
  + `client.app_package_name`
  + `env.platform_version`
  + `env.platform`
  + `env.make`
  + `env.model`
  + `env.locale`
  + `custom` – 由客户应用程序设置的自定义值。
+ `callbackWaitsForEmptyEventLoop`：默认情况下（`true`），当使用基于回调的函数处理程序时，Lambda 会在回调函数执行完毕后，等待事件循环为空，然后再结束函数调用。设置为 `false` 将发送响应并立即结束调用，而无需等待回调函数运行完毕后才让事件循环清空。未完成的事件将在下次调用期间继续运行。请注意，Lambda 仅支持针对 Node.js 22 及更早版本运行时系统的基于回调的函数处理程序。

以下示例函数记录了上下文信息并返回了日志的位置。

**Example index.js 文件**  

```
exports.handler = async function(event, context) {
  console.log('Remaining time: ', context.getRemainingTimeInMillis())
  console.log('Function name: ', context.functionName)
  return context.logStreamName
}
```

# Node.js Lambda 函数日志记录和监控
<a name="nodejs-logging"></a>

Amazon Lambda 将代表您自动监控 Lambda 函数并将日志记录发送至 Amazon CloudWatch。您的 Lambda 函数带有一个 CloudWatch Logs 日志组以及函数的每个实例的日志流。Lambda 运行时环境会将每个调用的详细信息发送到日志流，然后中继函数代码的日志和其他输出。有关更多信息，请参阅 [将 Lambda 函数日志发送到 CloudWatch Logs](monitoring-cloudwatchlogs.md)。

本页旨在介绍如何从 Lambda 函数的代码生成日志输出，并使用 Amazon Command Line Interface、Lambda 控制台或 CloudWatch 控制台访问日志。

**Topics**
+ [

## 创建返回日志的函数
](#node-logging-output)
+ [

## 在 Node.js 中使用 Lambda 高级日志记录控件
](#node-js-logging-advanced)
+ [

## 在 Lambda 控制台中查看日志
](#nodejs-logging-console)
+ [

## 在 CloudWatch 控制台中查看日志
](#nodejs-logging-cwconsole)
+ [

## 使用 Amazon Command Line Interface（Amazon CLI）查看日志
](#nodejs-logging-cli)
+ [

## 删除日志
](#nodejs-logging-delete)

## 创建返回日志的函数
<a name="node-logging-output"></a>

要从函数代码输出日志，您可以使用[控制台对象](https://developer.mozilla.org/en-US/docs/Web/API/Console)的方法或使用写入到 `stdout` 或 `stderr` 的任何日志记录库。以下示例记录环境变量和事件对象的值。

**注意**  
建议在记录输入时使用输入验证和输出编码等技术。如果直接记录输入数据，攻击者可能会利用您的代码，让篡改难以检测、伪造日志条目或绕过日志监视器。有关更多信息，请参阅《Common Weakness Enumeration》中的 [Improper Output Neutralization for Logs](https://cwe.mitre.org/data/definitions/117.html)。**

**Example index.js 文件 – 日志记录**  

```
exports.handler = async function(event, context) {
  console.log("ENVIRONMENT VARIABLES\n" + JSON.stringify(process.env, null, 2))
  console.info("EVENT\n" + JSON.stringify(event, null, 2))
  console.warn("Event not processed.")
  return context.logStreamName
}
```

**Example 日志格式**  

```
START RequestId: c793869b-ee49-115b-a5b6-4fd21e8dedac Version: $LATEST
2019-06-07T19:11:20.562Z	c793869b-ee49-115b-a5b6-4fd21e8dedac	INFO	ENVIRONMENT VARIABLES
{
  "AWS_LAMBDA_FUNCTION_VERSION": "$LATEST",
  "AWS_LAMBDA_LOG_GROUP_NAME": "/aws/lambda/my-function",
  "AWS_LAMBDA_LOG_STREAM_NAME": "2019/06/07/[$LATEST]e6f4a0c4241adcd70c262d34c0bbc85c",
  "AWS_EXECUTION_ENV": "AWS_Lambda_nodejs12.x",
  "AWS_LAMBDA_FUNCTION_NAME": "my-function",
  "PATH": "/var/lang/bin:/usr/local/bin:/usr/bin/:/bin:/opt/bin",
  "NODE_PATH": "/opt/nodejs/node10/node_modules:/opt/nodejs/node_modules:/var/runtime/node_modules",
  ...
}
2019-06-07T19:11:20.563Z	c793869b-ee49-115b-a5b6-4fd21e8dedac	INFO	EVENT
{
  "key": "value"
}
2019-06-07T19:11:20.564Z	c793869b-ee49-115b-a5b6-4fd21e8dedac	WARN	Event not processed.
END RequestId: c793869b-ee49-115b-a5b6-4fd21e8dedac
REPORT RequestId: c793869b-ee49-115b-a5b6-4fd21e8dedac	Duration: 128.83 ms	Billed Duration: 296 ms	Memory Size: 128 MB	Max Memory Used: 74 MB	Init Duration: 166.62 ms	XRAY TraceId: 1-5d9d007f-0a8c7fd02xmpl480aed55ef0	SegmentId: 3d752xmpl1bbe37e	Sampled: true
```

Node.js 运行时记录每次调用的 `START`、`END` 和 `REPORT` 行。它向函数记录的每个条目添加时间戳、请求 ID 和日志级别。报告行提供了以下详细信息。

**REPORT 行数据字段**
+ **RequestId** – 调用的唯一请求 ID。
+ **Duration**（持续时间）– 函数的处理程序方法处理事件所花费的时间。
+ **Billed Duration**（计费持续时间）– 针对调用计费的时间量。
+ **Memory Size**（内存大小）– 分配给函数的内存量。
+ **Max Memory Used**（最大内存使用量）– 函数使用的内存量。如果调用共享执行环境，Lambda 会报告所有调用使用的最大内存。此行为可能会导致报告值高于预期。
+ **Init Duration**（初始持续时间）– 对于提供的第一个请求，为运行时在处理程序方法外部加载函数和运行代码所花费的时间。
+ **XRAY TraceId** – 对于追踪的请求，为 [Amazon X-Ray 追踪 ID](services-xray.md)。
+ **SegmentId** – 对于追踪的请求，为 X-Ray 分段 ID。
+ **Sampled**（采样）– 对于跟踪的请求，为采样结果。

您可以在 Lambda 控制台中、在 CloudWatch Logs 控制台中或从命令行查看日志。

## 在 Node.js 中使用 Lambda 高级日志记录控件
<a name="node-js-logging-advanced"></a>

为了让您更好地控制如何捕获、处理和使用函数日志，您可以为支持的 Node.js 运行时系统配置以下日志记录选项：
+ **日志格式** - 为函数日志选择纯文本或结构化的 JSON 格式
+ **日志级别** - 对于 JSON 格式的日志，选择 Lambda 发送到 Amazon CloudWatch 的日志的详细信息级别，例如 ERROR、DEBUG 或 INFO
+ **日志组** - 选择您的函数发送日志的目标 CloudWatch 日志组

有关这些日志记录选项的更多信息以及如何通过配置来使用函数的说明，请参阅 [为 Lambda 函数配置高级日志记录控件](monitoring-logs.md#monitoring-cloudwatchlogs-advanced)。

要在 Node.js Lambda 函数中使用日志格式和日志级别选项，请参阅以下各节中的指南。

### 在 Node.js 中使用结构化的 JSON 日志
<a name="nodejs-logging-advanced-JSON"></a>

如果您为函数的日志格式选择 JSON，Lambda 将使用 `console.trace`、`console.debug`、`console.log`、`console.info`、`console.error` 和 `console.warn` 的控制台方法将日志输出作为结构化 JSON 发送到 CloudWatch。每个 JSON 日志对象包含至少四个键值对和以下键：
+ `"timestamp"` - 生成日志消息的时间
+ `"level"` - 分配给消息的日志级别
+ `"message"` - 日志消息的内容
+ `"requestId"` - 函数调用的唯一请求 ID

根据函数使用的日志记录方法，此 JSON 对象还可能包含其他密钥对。例如，如果函数通过 `console` 方法使用多个参数记录错误对象，则 JSON 对象将包含带有键 `errorMessage`、`errorType`、和 `stackTrace` 的额外键值对。

如果您的代码已经使用其他日志记录库（例如 Powertools for Amazon Lambda）来生成 JSON 结构化日志，则无需进行任何更改。Lambda 不会对任何已采用 JSON 编码的日志进行双重编码，因此仍将像以前一样捕获函数的应用程序日志。

有关使用 Powertools for Amazon Lambda 日志记录包在 Node.js 运行时系统中创建 JSON 结构化日志的更多信息，请参阅 [TypeScript Lambda 函数日志记录和监控](typescript-logging.md)。

#### JSON 格式的日志输出示例
<a name="nodejs-logging-examples"></a>

以下示例显示了当您将函数的日志格式设置为 JSON 时，如何在 CloudWatch Logs 中捕获使用具有单个和多个参数的 `console` 方法生成的各种日志输出。

第一个示例使用 `console.error` 方法输出一个简单的字符串。

**Example Node.js 日志记录代码**  

```
export const handler = async (event) => {
  console.error("This is a warning message");
  ...
}
```

**Example JSON 日志记录**  

```
{
    "timestamp":"2025-11-01T00:21:51.358Z",
    "level":"ERROR",
    "message":"This is a warning message",
    "requestId":"93f25699-2cbf-4976-8f94-336a0aa98c6f"
}
```

您还可以使用 `console` 方法中的单个或多个参数输出更复杂的结构化日志消息。在下一个示例中，您可以使用 `console.log` 的单个参数输出两个键值对。请注意，Lambda 发送到 CloudWatch Logs 的 JSON 对象中的 `"message"` 字段未进行字符串化。

**Example Node.js 日志记录代码**  

```
export const handler = async (event) => {
  console.log({data: 12.3, flag: false});
  ...
}
```

**Example JSON 日志记录**  

```
{
    "timestamp": "2025-12-08T23:21:04.664Z",
    "level": "INFO",
    "requestId": "405a4537-9226-4216-ac59-64381ec8654a",
    "message": {
        "data": 12.3,
        "flag": false
    }
}
```

在下一个示例中，您可以再次使用 `console.log` 方法创建日志输出。这次，该方法采用两个参数，即一个包含两个键值对的映射和一个标识字符串。请注意，在本例中，由于您提供了两个参数，因此 Lambda 会对 `"message"` 字段进行字符串化。

**Example Node.js 日志记录代码**  

```
export const handler = async (event) => {
  console.log('Some object - ', {data: 12.3, flag: false});
  ...
}
```

**Example JSON 日志记录**  

```
{
    "timestamp": "2025-12-08T23:21:04.664Z",
    "level": "INFO",
    "requestId": "405a4537-9226-4216-ac59-64381ec8654a",
    "message": "Some object -  { data: 12.3, flag: false }"
}
```

Lambda 为使用 `console.log` 生成的输出分配日志级别 INFO。

最后一个示例说明了如何使用 `console` 方法将错误对象输出到 CloudWatch Logs。请注意，当您使用多个参数记录错误对象时，Lambda 会将字段 `errorMessage`、`errorType` 和 `stackTrace` 添加到日志输出中。

**Example Node.js 日志记录代码**  

```
export const handler = async (event) => {
  let e1 = new ReferenceError("some reference error");
  let e2 = new SyntaxError("some syntax error");
  console.log(e1);
  console.log("errors logged - ", e1, e2);
};
```

**Example JSON 日志记录**  

```
{
    "timestamp": "2025-12-08T23:21:04.632Z",
    "level": "INFO",
    "requestId": "405a4537-9226-4216-ac59-64381ec8654a",
    "message": {
        "errorType": "ReferenceError",
        "errorMessage": "some reference error",
        "stackTrace": [
            "ReferenceError: some reference error",
            "    at Runtime.handler (file:///var/task/index.mjs:3:12)",
            "    at Runtime.handleOnceNonStreaming (file:///var/runtime/index.mjs:1173:29)"
        ]
    }
}

{
    "timestamp": "2025-12-08T23:21:04.646Z",
    "level": "INFO",
    "requestId": "405a4537-9226-4216-ac59-64381ec8654a",
    "message": "errors logged -  ReferenceError: some reference error\n    at Runtime.handler (file:///var/task/index.mjs:3:12)\n    at Runtime.handleOnceNonStreaming 
    (file:///var/runtime/index.mjs:1173:29) SyntaxError: some syntax error\n    at Runtime.handler (file:///var/task/index.mjs:4:12)\n    at Runtime.handleOnceNonStreaming 
    (file:///var/runtime/index.mjs:1173:29)",
    "errorType": "ReferenceError",
    "errorMessage": "some reference error",
    "stackTrace": [
        "ReferenceError: some reference error",
        "    at Runtime.handler (file:///var/task/index.mjs:3:12)",
        "    at Runtime.handleOnceNonStreaming (file:///var/runtime/index.mjs:1173:29)"
    ]
}
```

记录多种错误类型时，会从提供给 `console` 方法的第一个错误类型中提取额外的 `errorMessage`、`errorType` 和 `stackTrace` 字段。

### 使用带有结构化的 JSON 日志的嵌入式指标格式（EMF）客户端库
<a name="nodejs-logging-advanced-emf"></a>

Amazon 提供了用于 Node.js 的开源客户端库，可供您用来创建[嵌入式指标格式](https://docs.amazonaws.cn/AmazonCloudWatch/latest/monitoring/CloudWatch_Embedded_Metric_Format_Libraries.html)（EMF）日志。如果您有使用这些库的现有函数，并且将函数的日志格式更改为 JSON，则 CloudWatch 可能无法再识别您的代码发出的指标。

如果您的代码当前直接使用 `console.log` 或使用 Powertools for Amazon Lambda（TypeScript） 发出 EMF 日志，若将函数的日志格式更改为 JSON，CloudWatch 也将无法解析这些日志。

**重要**  
为确保 CloudWatch 继续正确解析函数的 EMF 日志，请将库的 [EMF](https://www.npmjs.com/package/aws-embedded-metrics) 和 [Powertools for Amazon Lambda](https://github.com/aws-powertools/powertools-lambda-typescript) 更新到最新版本。如果切换到 JSON 日志格式，我们还建议您进行测试以确保与函数的嵌入式指标兼容。如果您的代码直接使用 `console.log` 发出 EMF 日志，请更改您的代码以将这些指标直接输出到 `stdout`，如以下示例代码所示。

**Example 向 `stdout` 发送嵌入式指标的代码**  

```
process.stdout.write(JSON.stringify(
    {
        "_aws": {
            "Timestamp": Date.now(),
            "CloudWatchMetrics": [{
                "Namespace": "lambda-function-metrics",
                "Dimensions": [["functionVersion"]],
                "Metrics": [{
                    "Name": "time",
                    "Unit": "Milliseconds",
                    "StorageResolution": 60
                }]
            }]
        },
        "functionVersion": "$LATEST",
        "time": 100,
        "requestId": context.awsRequestId
    }
) + "\n")
```

### 在 Node.js 中使用日志级别筛选
<a name="nodejs-logging-advanced-level"></a>

为了让 Amazon Lambda 根据日志级别筛选应用程序日志，您的函数必须使用 JSON 格式的日志。您可以通过两种方式实现这一点：
+ 使用标准控制台方法创建日志输出，并将您的函数配置为使用 JSON 日志格式。然后 Amazon Lambda 使用 [在 Node.js 中使用结构化的 JSON 日志](#nodejs-logging-advanced-JSON) 中所述 JSON 对象中的“级别”键值对筛选日志输出。要了解如何配置函数的日志格式，请参阅 [为 Lambda 函数配置高级日志记录控件](monitoring-logs.md#monitoring-cloudwatchlogs-advanced)。
+ 使用其他日志记录库或方法在代码中创建 JSON 结构化日志，其中包含定义日志输出级别的“级别”键值对。例如，您可以使用 Powertools for Amazon Lambda 通过代码生成 JSON 结构化日志输出。要了解有关在 Node.js 运行时系统中使用 Powertools 的更多信息，请参阅 [TypeScript Lambda 函数日志记录和监控](typescript-logging.md)。

  要让 Lambda 筛选函数的日志，还必须在 JSON 日志输出中包含一个 `"timestamp"` 键值对。必须以有效的 [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) 时间戳格式指定时间。如果您未提供有效的时间戳，Lambda 将为日志分配 INFO 级别并为您添加时间戳。

将函数配置为使用日志级别筛选时，您可以从以下选项中选择希望 Amazon Lambda 发送到 CloudWatch Logs 的日志级别：


| 日志级别 | 标准使用情况 | 
| --- | --- | 
| TRACE（最详细） | 用于跟踪代码执行路径的最精细信息 | 
| DEBUG | 系统调试的详细信息 | 
| INFO | 记录函数正常运行情况的消息 | 
| 警告 | 有关潜在错误的消息，如果不加以解决，这些错误可能会导致意外行为 | 
| ERROR | 有关会阻碍代码按预期执行的问题的消息 | 
| FATAL（最简略） | 有关导致应用程序停止运行的严重错误的消息 | 

Lambda 仅将选定级别及更低级别的系统日志发送到 CloudWatch。例如，如果您将日志级别配置为 WARN，Lambda 将发送与 WARN、ERROR 和 FATAL 级别相对应的日志。

## 在 Lambda 控制台中查看日志
<a name="nodejs-logging-console"></a>

调用 Lambda 函数后，您可以使用 Lambda 控制台查看日志输出。

如果可以在嵌入式**代码**编辑器中测试代码，则可以在**执行结果**中找到日志。使用控制台测试功能调用函数时，可以在**详细信息**部分找到**日志输出**。

## 在 CloudWatch 控制台中查看日志
<a name="nodejs-logging-cwconsole"></a>

您可以使用 Amazon CloudWatch 控制台查看所有 Lambda 函数调用的日志。

**使用 CloudWatch 控制台查看日志**

1. 打开 CloudWatch 控制台的 [Log groups](https://console.amazonaws.cn/cloudwatch/home?#logs:)（日志组页面）。

1. 选择您的函数 (**/aws/lambda/*your-function-name***) 的日志组。

1. 创建日志流。

每个日志流对应一个[函数实例](lambda-runtime-environment.md)。日志流会在您更新 Lambda 函数以及创建更多实例来处理并发调用时显示。要查找特定调用的日志，建议您使用 Amazon X-Ray 检测函数。X-Ray 会在追踪中记录有关请求和日志流的详细信息。

## 使用 Amazon Command Line Interface（Amazon CLI）查看日志
<a name="nodejs-logging-cli"></a>

Amazon CLI 是一种开源工具，让您能够在命令行 Shell 中使用命令与 Amazon 服务进行交互。要完成本节中的步骤，您必须拥有 [Amazon CLI 版本 2](https://docs.amazonaws.cn/cli/latest/userguide/getting-started-install.html)。

您可以通过 [Amazon CLI](https://docs.amazonaws.cn/cli/latest/userguide/cli-chap-welcome.html)，使用 `--log-type` 命令选项检索调用的日志。响应包含一个 `LogResult` 字段，其中包含多达 4KB 来自调用的 base64 编码日志。

**Example 检索日志 ID**  
以下示例说明如何从 `LogResult` 字段中检索名为 `my-function` 的函数的*日志 ID*。  

```
aws lambda invoke --function-name my-function out --log-type Tail
```
您应看到以下输出：  

```
{
    "StatusCode": 200,
    "LogResult": "U1RBUlQgUmVxdWVzdElkOiA4N2QwNDRiOC1mMTU0LTExZTgtOGNkYS0yOTc0YzVlNGZiMjEgVmVyc2lvb...",
    "ExecutedVersion": "$LATEST"
}
```

**Example 解码日志**  
在同一命令提示符下，使用 `base64` 实用程序解码日志。以下示例说明如何为 `my-function` 检索 base64 编码的日志。  

```
aws lambda invoke --function-name my-function out --log-type Tail \
--query 'LogResult' --output text --cli-binary-format raw-in-base64-out | base64 --decode
```
如果使用 **cli-binary-format** 版本 2，则 Amazon CLI 选项是必需的。要将其设为默认设置，请运行 `aws configure set cli-binary-format raw-in-base64-out`。有关更多信息，请参阅*版本 2 的 Amazon Command Line Interface 用户指南*中的 [Amazon CLI 支持的全局命令行选项](https://docs.amazonaws.cn/cli/latest/userguide/cli-configure-options.html#cli-configure-options-list)。  
您应看到以下输出：  

```
START RequestId: 57f231fb-1730-4395-85cb-4f71bd2b87b8 Version: $LATEST
"AWS_SESSION_TOKEN": "AgoJb3JpZ2luX2VjELj...", "_X_AMZN_TRACE_ID": "Root=1-5d02e5ca-f5792818b6fe8368e5b51d50;Parent=191db58857df8395;Sampled=0"",ask/lib:/opt/lib",
END RequestId: 57f231fb-1730-4395-85cb-4f71bd2b87b8
REPORT RequestId: 57f231fb-1730-4395-85cb-4f71bd2b87b8  Duration: 79.67 ms      Billed Duration: 80 ms         Memory Size: 128 MB     Max Memory Used: 73 MB
```
`base64` 实用程序在 Linux、macOS 和 [Ubuntu on Windows](https://docs.microsoft.com/en-us/windows/wsl/install-win10) 上可用。macOS 用户可能需要使用 `base64 -D`。

**Example get-logs.sh 脚本**  
在同一命令提示符下，使用以下脚本下载最后五个日志事件。此脚本使用 `sed` 从输出文件中删除引号，并休眠 15 秒以等待日志可用。输出包括来自 Lambda 的响应，以及来自 `get-log-events` 命令的输出。  
复制以下代码示例的内容并将其作为 `get-logs.sh` 保存在 Lambda 项目目录中。  
如果使用 **cli-binary-format** 版本 2，则 Amazon CLI 选项是必需的。要将其设为默认设置，请运行 `aws configure set cli-binary-format raw-in-base64-out`。有关更多信息，请参阅*版本 2 的 Amazon Command Line Interface 用户指南*中的 [Amazon CLI 支持的全局命令行选项](https://docs.amazonaws.cn/cli/latest/userguide/cli-configure-options.html#cli-configure-options-list)。  

```
#!/bin/bash
aws lambda invoke --function-name my-function --cli-binary-format raw-in-base64-out --payload '{"key": "value"}' out
sed -i'' -e 's/"//g' out
sleep 15
aws logs get-log-events --log-group-name /aws/lambda/my-function --log-stream-name stream1 --limit 5
```

**Example macOS 和 Linux（仅限）**  
在同一命令提示符下，macOS 和 Linux 用户可能需要运行以下命令以确保脚本可执行。  

```
chmod -R 755 get-logs.sh
```

**Example 检索最后五个日志事件**  
在同一命令提示符下，运行以下脚本以获取最后五个日志事件。  

```
./get-logs.sh
```
您应看到以下输出：  

```
{
    "StatusCode": 200,
    "ExecutedVersion": "$LATEST"
}
{
    "events": [
        {
            "timestamp": 1559763003171,
            "message": "START RequestId: 4ce9340a-b765-490f-ad8a-02ab3415e2bf Version: $LATEST\n",
            "ingestionTime": 1559763003309
        },
        {
            "timestamp": 1559763003173,
            "message": "2019-06-05T19:30:03.173Z\t4ce9340a-b765-490f-ad8a-02ab3415e2bf\tINFO\tENVIRONMENT VARIABLES\r{\r  \"AWS_LAMBDA_FUNCTION_VERSION\": \"$LATEST\",\r ...",
            "ingestionTime": 1559763018353
        },
        {
            "timestamp": 1559763003173,
            "message": "2019-06-05T19:30:03.173Z\t4ce9340a-b765-490f-ad8a-02ab3415e2bf\tINFO\tEVENT\r{\r  \"key\": \"value\"\r}\n",
            "ingestionTime": 1559763018353
        },
        {
            "timestamp": 1559763003218,
            "message": "END RequestId: 4ce9340a-b765-490f-ad8a-02ab3415e2bf\n",
            "ingestionTime": 1559763018353
        },
        {
            "timestamp": 1559763003218,
            "message": "REPORT RequestId: 4ce9340a-b765-490f-ad8a-02ab3415e2bf\tDuration: 26.73 ms\tBilled Duration: 27 ms \tMemory Size: 128 MB\tMax Memory Used: 75 MB\t\n",
            "ingestionTime": 1559763018353
        }
    ],
    "nextForwardToken": "f/34783877304859518393868359594929986069206639495374241795",
    "nextBackwardToken": "b/34783877303811383369537420289090800615709599058929582080"
}
```

## 删除日志
<a name="nodejs-logging-delete"></a>

删除函数时，日志组不会自动删除。要避免无限期存储日志，请删除日志组，或[配置一个保留期](https://docs.amazonaws.cn/AmazonCloudWatch/latest/logs/Working-with-log-groups-and-streams.html#SettingLogRetention)，在该保留期之后，日志将自动删除。

# 在 Amazon Lambda 中检测 Node.js 代码
<a name="nodejs-tracing"></a>

Lambda 与 Amazon X-Ray 集成，以帮助您跟踪、调试和优化 Lambda 应用程序。您可以在某个请求遍历应用程序中的资源（其中可能包括 Lambda 函数和其他 Amazon 服务）时，使用 X-Ray 跟踪该请求。

要将跟踪数据发送到 X-Ray，您可以使用以下两个软件开发工具包 (SDK) 库之一：
+ [适用于 OpenTelemetry 的 Amazon 发行版 (ADOT)](https://www.amazonaws.cn/otel) – 一种安全、可供生产、支持 Amazon 的 OpenTelemetry (OTel) SDK 的分发版本。
+ [Amazon X-Ray SDK for Node.js](https://docs.amazonaws.cn/xray/latest/devguide/xray-sdk-nodejs.html) – 用于生成跟踪数据并将其发送到 X-Ray 的 SDK

每个开发工具包均提供了将遥测数据发送到 X-Ray 服务的方法。然后，您可以使用 X-Ray 查看、筛选和获得对应用程序性能指标的洞察，从而发现问题和优化机会。

**重要**  
X-Ray 和 Powertools for Amazon Lambda SDK 是 Amazon 提供的紧密集成的分析解决方案的一部分。ADOT Lambda Layers 是全行业通用的跟踪分析标准的一部分，该标准通常会收集更多数据，但可能不适用于所有使用案例。您可以使用任一解决方案在 X-Ray 中实现端到端跟踪。要了解有关如何在两者之间进行选择的更多信息，请参阅[在 Amazon Distro for Open Telemetry 和 X-Ray 开发工具包之间进行选择](https://docs.amazonaws.cn/xray/latest/devguide/xray-instrumenting-your-app.html#xray-instrumenting-choosing)。

**Topics**
+ [

## 使用 ADOT 分析您的 Node.js 函数
](#nodejs-adot)
+ [

## 使用 X-Ray SDK 分析您的 Node.js 函数
](#nodejs-xray-sdk)
+ [

## 使用 Lambda 控制台激活跟踪
](#nodejs-tracing-console)
+ [

## 使用 Lambda API 激活跟踪
](#nodejs-tracing-api)
+ [

## 使用 Amazon CloudFormation 激活跟踪
](#nodejs-tracing-cloudformation)
+ [

## 解释 X-Ray 跟踪
](#nodejs-tracing-interpretation)
+ [

## 在层中存储运行时依赖项 (X-Ray SDK)
](#nodejs-tracing-layers)

## 使用 ADOT 分析您的 Node.js 函数
<a name="nodejs-adot"></a>

ADOT 提供完全托管式 Lambda [层](chapter-layers.md)，这些层使用 OTel SDK，将收集遥测数据所需的一切内容打包起来。通过使用此层，您可以在不必修改任何函数代码的情况下，对您的 Lambda 函数进行分析。您还可以将您的层配置为对 OTel 进行自定义初始化。有关更多信息，请参阅 ADOT 文档中的[适用于 Lambda 上的 ADOT 收集器的自定义配置](https://aws-otel.github.io/docs/getting-started/lambda#custom-configuration-for-the-adot-collector-on-lambda)。

对于 Node.js 运行时，可以添加 **适用于 ADOT Javascript 的 Amazon 托管 Lambda 层**以自动分析您的函数。有关如何添加此层的详细说明，请参阅 ADOT 文档中的 [Amazon Distro for OpenTelemetry Lambda 对 JavaScript 的支持](https://aws-otel.github.io/docs/getting-started/lambda/lambda-js)。

## 使用 X-Ray SDK 分析您的 Node.js 函数
<a name="nodejs-xray-sdk"></a>

要记录有关您的 Lambda 函数对应用程序中的其他资源进行调用的详细信息，您还可以使用 Amazon X-Ray SDK for Node.js。要获取开发工具包，请将 `aws-xray-sdk-core` 包添加到应用程序的依赖项中。

**Example [blank-nodejs/package.json](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/blank-nodejs/package.json)**  

```
{
  "name": "blank-nodejs",
  "version": "1.0.0",
  "private": true,
  "devDependencies": {
    "jest": "29.7.0"
  },
  "dependencies": {
    "@aws-sdk/client-lambda": "3.345.0",
    "aws-xray-sdk-core": "3.5.3"
  },
  "scripts": {
    "test": "jest"
  }
}
```

要在 [适用于 JavaScript 的 Amazon SDK v3](https://docs.amazonaws.cn/sdk-for-javascript/v3/developer-guide/welcome.html) 中检测 Amazon SDK 客户端，请使用 `captureAWSv3Client` 方法封装客户端实例。

**Example [blank-nodejs/function/index.js](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/blank-nodejs/function/index.js) – 跟踪Amazon开发工具包客户端**  

```
const AWSXRay = require('aws-xray-sdk-core');
const { LambdaClient, GetAccountSettingsCommand } = require('@aws-sdk/client-lambda');

// Create client outside of handler to reuse
const lambda = AWSXRay.captureAWSv3Client(new LambdaClient());

// Handler
exports.handler = async function(event, context) {
    event.Records.forEach(record => {
  ...
```

Lambda 运行时设置一些环境变量来配置 X-Ray 开发工具包。例如，Lambda 将 `AWS_XRAY_CONTEXT_MISSING` 设置为 `LOG_ERROR`，以避免从 X-Ray 开发工具包引发运行时错误。要设置自定义上下文缺失策略，请覆盖函数配置中的环境变量以使其没有值，然后可以通过编程方式设置上下文缺失策略。

**Example 初始化代码示例**  

```
const AWSXRay = require('aws-xray-sdk-core');

// Configure the context missing strategy to do nothing
AWSXRay.setContextMissingStrategy(() => {});
```

有关更多信息，请参阅 [使用 Lambda 环境变量](configuration-envvars.md)。

在添加正确的依赖项并进行必要的代码更改后，请通过 Lambda 控制台或 API 激活函数配置中的跟踪。

## 使用 Lambda 控制台激活跟踪
<a name="nodejs-tracing-console"></a>

要使用控制台切换 Lambda 函数的活动跟踪，请按照以下步骤操作：

**打开活跃跟踪**

1. 打开 Lamba 控制台的[函数](https://console.amazonaws.cn/lambda/home#/functions)页面。

1. 选择函数。

1. 选择 **Configuration**（配置），然后选择 **Monitoring and operations tools**（监控和操作工具）。

1. 在**其他监控工具**下，选择**编辑**。

1. 在 **CloudWatch 应用程序信号和 Amazon X-Ray** 下，为 **Lambda 服务跟踪**选择**启用**。

1. 选择**保存**。

## 使用 Lambda API 激活跟踪
<a name="nodejs-tracing-api"></a>

借助 Amazon CLI 或 Amazon SDK 在 Lambda 函数上配置跟踪，请使用以下 API 操作：
+ [UpdateFunctionConfiguration](https://docs.amazonaws.cn/lambda/latest/api/API_UpdateFunctionConfiguration.html)
+ [GetFunctionConfiguration](https://docs.amazonaws.cn/lambda/latest/api/API_GetFunctionConfiguration.html)
+ [CreateFunction](https://docs.amazonaws.cn/lambda/latest/api/API_CreateFunction.html)

以下示例 Amazon CLI 命令对名为 **my-function** 的函数启用活跃跟踪。

```
aws lambda update-function-configuration --function-name my-function \
--tracing-config Mode=Active
```

跟踪模式是发布函数版本时版本特定配置的一部分。您无法更改已发布版本上的跟踪模式。

## 使用 Amazon CloudFormation 激活跟踪
<a name="nodejs-tracing-cloudformation"></a>

要对 Amazon CloudFormation 模板中的 `AWS::Lambda::Function` 资源激活跟踪，请使用 `TracingConfig` 属性。

**Example [function-inline.yml](https://github.com/awsdocs/aws-lambda-developer-guide/blob/master/templates/function-inline.yml) – 跟踪配置**  

```
Resources:
  function:
    Type: [AWS::Lambda::Function](https://docs.amazonaws.cn/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-function.html)
    Properties:
      TracingConfig:
        Mode: Active
      ...
```

对于 Amazon Serverless Application Model (Amazon SAM) `AWS::Serverless::Function` 资源，请使用 `Tracing` 属性。

**Example [template.yml](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/blank-nodejs/template.yml) – 跟踪配置**  

```
Resources:
  function:
    Type: [AWS::Serverless::Function](https://docs.amazonaws.cn/serverless-application-model/latest/developerguide/sam-resource-function.html)
    Properties:
      Tracing: Active
      ...
```

## 解释 X-Ray 跟踪
<a name="nodejs-tracing-interpretation"></a>

您的函数需要权限才能将跟踪数据上载到 X-Ray。在 Lambda 控制台中激活跟踪后，Lambda 会将所需权限添加到函数的[执行角色](lambda-intro-execution-role.md)。如果没有，请将 [AWSXRayDaemonWriteAccess](https://console.amazonaws.cn/iam/home#/policies/arn:aws:iam::aws:policy/AWSXRayDaemonWriteAccess) 策略添加到执行角色。

在配置活跃跟踪后，您可以通过应用程序观察特定请求。[X-Ray 服务图](https://docs.amazonaws.cn/xray/latest/devguide/aws-xray.html#xray-concepts-servicegraph)将显示有关应用程序及其所有组件的信息。以下示例显示了具有两个函数的应用程序。主函数处理事件，有时会返回错误。位于顶部的第二个函数将处理第一个函数的日志组中显示的错误，并使用 Amazon SDK 调用 X-Ray、Amazon Simple Storage Service (Amazon S3) 和 Amazon CloudWatch Logs。

![\[\]](http://docs.amazonaws.cn/lambda/latest/dg/images/sample-errorprocessor-servicemap.png)


X-Ray 无法跟踪对应用程序的所有请求。X-Ray 将应用采样算法确保跟踪有效，同时仍会提供所有请求的一个代表性样本。采样率是每秒 1 个请求和 5% 的其他请求。您无法为函数配置此 X-Ray 采样率。

在 X-Ray 中，*跟踪*记录有关由一个或多个*服务*处理的请求的信息。Lambda 会每个跟踪记录 2 个分段，这些分段将在服务图上创建两个节点。下图突出显示了这两个节点：

![\[\]](http://docs.amazonaws.cn/lambda/latest/dg/images/xray-servicemap-function.png)


位于左侧的第一个节点表示接收调用请求的 Lambda 服务。第二个节点表示特定的 Lambda 函数。以下示例显示了一个包含这 2 个分段的跟踪。两者都命名为 **my-function**，但其中一个函数具有 `AWS::Lambda` 源，另一个则具有 `AWS::Lambda::Function` 源。如果 `AWS::Lambda` 分段显示错误，则表示 Lambda 服务存在问题。如果 `AWS::Lambda::Function` 分段显示错误，则说明函数存在问题。

![\[\]](http://docs.amazonaws.cn/lambda/latest/dg/images/V2_sandbox_images/my-function-2-v1.png)


此示例将展开 `AWS::Lambda::Function` 分段，以显示其三个子分段。

**注意**  
Amazon 目前正在实施对 Lambda 服务的更改。由于这些更改，您可能会看到 Amazon Web Services 账户 中不同 Lambda 函数发出的系统日志消息和跟踪分段的结构和内容之间存在细微差异。  
此处显示的示例跟踪说明了旧样式函数分段。以下段落介绍了新旧样式分段之间的差异。  
这些更改将在未来几周内实施，除中国和 GovCloud 区域外，所有 Amazon Web Services 区域 的函数都将过渡到使用新格式的日志消息和跟踪分段。

旧样式函数分段包含以下子分段：
+ **初始化** – 表示加载函数和运行[初始化代码](foundation-progmodel.md)所花费的时间。此子分段仅对由您的函数的每个实例处理的第一个事件显示。
+ **调用** – 表示执行处理程序代码花费的时间。
+ **开销** – 表示 Lambda 运行时为准备处理下一个事件而花费的时间。

新样式函数分段不包含 `Invocation` 子分段。而是将客户子分段直接附加到函数分段。有关新旧样式函数分段结构的更多信息，请参阅 [了解 X-Ray 跟踪](services-xray.md#services-xray-traces)。

您还可以分析 HTTP 客户端、记录 SQL 查询以及使用注释和元数据创建自定义子段。有关更多信息，请参阅 *Amazon X-Ray 开发人员指南*中的 [Amazon X-Ray SDK for Node.js](https://docs.amazonaws.cn/xray/latest/devguide/xray-sdk-nodejs.html)。

**定价**  
作为 Amazon 免费套餐的组成部分，您可以每月免费使用 X-Ray 跟踪，但不能超过一定限制。超出该阈值后，X-Ray 会对跟踪存储和检索进行收费。有关更多信息，请参阅 [Amazon X-Ray 定价](https://www.amazonaws.cn/xray/pricing/)。

## 在层中存储运行时依赖项 (X-Ray SDK)
<a name="nodejs-tracing-layers"></a>

如果您使用 X-Ray 开发工具包来分析Amazon开发工具包客户端和您的函数代码，则您的部署程序包可能会变得相当大。为了避免每次更新函数代码时上载运行时依赖项，请将 X-Ray SDK 打包到 [Lambda 层](chapter-layers.md)中。

以下示例显示存储 Amazon X-Ray SDK for Node.js 的 `AWS::Serverless::LayerVersion` 资源。

**Example [template.yml](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/blank-nodejs/template.yml) – 依赖项层**  

```
Resources:
  function:
    Type: [AWS::Serverless::Function](https://docs.amazonaws.cn/serverless-application-model/latest/developerguide/sam-resource-function.html)
    Properties:
      CodeUri: function/.
      Tracing: Active
      Layers:
        - !Ref libs
      ...
  libs:
    Type: [AWS::Serverless::LayerVersion](https://docs.amazonaws.cn/serverless-application-model/latest/developerguide/sam-resource-layerversion.html)
    Properties:
      LayerName: blank-nodejs-lib
      Description: Dependencies for the blank sample app.
      ContentUri: lib/.
      CompatibleRuntimes:
        - nodejs24.x
```

使用此配置，仅在更改运行时依赖项时您才会更新库层。由于函数部署软件包仅包含您的代码，因此可以帮助缩短上传时间。

为依赖项创建层需要更改构建才能在部署之前生成层存档。有关工作示例，请参阅 [blank-nodejs](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/blank-nodejs) 示例应用程序。