

# 使用 TypeScript 构建 Lambda 函数
<a name="lambda-typescript"></a>

你可以使用 Node.js 运行时在 AWS Lambda 中运行 TypeScript 代码。由于 Node.js 不会在本机运行 TypeScript 代码，因此必须首先将 TypeScript 代码转换为 JavaScript。然后，可以使用 JavaScript 文件将您的函数代码部署到 Lambda。您的代码将在包含适用于 JavaScript 的 AWS SDK 的环境中运行，其中包含来自您管理的 AWS Identity and Access Management (IAM) 角色的凭证。要了解有关 Node.js 运行时随附的 SDK 版本的更多信息，请参阅 [包含运行时的 SDK 版本](lambda-nodejs.md#nodejs-sdk-included)。

Lambda 支持以下 Node.js 运行时。


| 名称 | 标识符 | 操作系统 | 弃用日期 | 阻止函数创建 | 阻止函数更新 | 
| --- | --- | --- | --- | --- | --- | 
|  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   | 

**Topics**
+ [

## 设置 TypeScript 开发环境
](#typescript-dev)
+ [

## Lambda 的类型定义
](#typescript-type-definitions)
+ [

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

# 使用 .zip 文件归档部署在 Lambda 中转换的 TypeScript 代码
](typescript-package.md)
+ [

# 使用容器镜像在 Lambda 中部署转换后的 TypeScript 代码
](typescript-image.md)
+ [

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

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

# 追踪 AWS Lambda 中的 TypeScript 代码
](typescript-tracing.md)

## 设置 TypeScript 开发环境
<a name="typescript-dev"></a>

使用本地集成式开发环境（IDE）或文本编辑器来编写 TypeScript 函数代码。您无法在 Lambda 控制台上创建 TypeScript 代码。

您可以使用 [esbuild](https://esbuild.github.io/) 或 Microsoft 的 TypeScript 编译器（`tsc`）将您的 TypeScript 代码转换为 JavaScript。[AWS Serverless Application Model（AWS SAM）](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-getting-started.html) 和 [AWS Cloud Development Kit (AWS CDK)](https://docs.aws.amazon.com/cdk/v2/guide/getting_started.html) 都使用 esbuild。

在使用 esbuild 时，请注意以下事项：
+ 有几个 [TypeScript 注意事项](https://esbuild.github.io/content-types/#typescript-caveats)。
+ 您必须配置 TypeScript 转换设置，以匹配您计划使用的 Node.js 运行时。有关更多信息，请参阅 esbuild 文档中的[目标](https://esbuild.github.io/api/#target)。有关演示如何将 Lambda 支持的特定 Node.js 版本设为目标的 **tsconfig.json** 文件示例，请参阅 [TypeScript GitHub 存储库](https://github.com/tsconfig/bases/blob/main/bases/node14.json)。
+ esbuild 不执行类型检查。要检查类型，请使用 `tsc` 编译器。运行 `tsc -noEmit` 或将 `"noEmit"` 参数添加到您的 **tsconfig.json** 文件，如以下示例中所示。这会将 `tsc` 配置为不发出 JavaScript 文件。在检查类型后，使用 esbuild 将 TypeScript 文件转换为 JavaScript。

**Example tsconfig.json**  

```
 {
  "compilerOptions": {
    "target": "es2020",
    "strict": true,
    "preserveConstEnums": true,
    "noEmit": true,
    "sourceMap": false,
    "module":"commonjs",
    "moduleResolution":"node",
    "esModuleInterop": true, 
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true, 
    "isolatedModules": true, 
  },
  "exclude": ["node_modules", "**/*.test.ts"]
}
```

## Lambda 的类型定义
<a name="typescript-type-definitions"></a>

[@types/aws-lambda](https://www.npmjs.com/package/@types/aws-lambda) 程序包为 Lambda 函数提供类型定义。如果您的函数使用以下任何一项，请安装此程序包：
+ 常见 AWS 事件源，例如：
  + `APIGatewayProxyEvent`：适用于 [Amazon API Gateway 代理集成](https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html) 
  + `SNSEvent`：适用于 [Amazon Simple Notification Service 通知](with-sns.md)
  + `SQSEvent`：适用于 [Amazon Simple Queue Service 消息](with-sqs.md)
  + `S3Event`：适用于 [S3 触发事件](with-s3.md)
  + `DynamoDBStreamEvent`：适用于 [Amazon DynamoDB Streams](with-ddb.md)
+ Lambda [上下文](typescript-context.md)对象
+ [回调](typescript-handler.md#typescript-handler-callback)处理程序模式

要将 Lambda 类型定义添加到您的函数中，请将 `@types/aws-lambda` 作为开发依赖项进行安装：

```
npm install -D @types/aws-lambda
```

然后，从 `aws-lambda` 导入这些类型：

```
import { Context, S3Event, APIGatewayProxyEvent } from 'aws-lambda';

export const handler = async (event: S3Event, context: Context) => {
    // Function code
};
```

`import ... from 'aws-lambda'` 语句会导入类型定义。但它不会导入 `aws-lambda` npm 程序包，这是一个无关的第三方工具。有关更多信息，请参阅 DefinitelyTyped GitHub 存储库中的 [aws-lambda](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/aws-lambda)。

**注意**  
使用自己的自定义类型定义时，无需使用 [@types/aws-lambda](https://www.npmjs.com/package/@types/aws-lambda)。有关为事件对象定义其自身类型的示例函数，请参阅 [示例 TypeScript Lambda 函数代码](typescript-handler.md#typescript-example-code)。

# 定义采用 TypeScript 的 Lambda 函数处理程序
<a name="typescript-handler"></a>

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

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

**Topics**
+ [

## 设置 TypeScript 项目
](#typescript-handler-setup)
+ [

## 示例 TypeScript Lambda 函数代码
](#typescript-example-code)
+ [

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

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

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

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

## TypeScript 函数的有效处理程序模式
](#typescript-handler-signatures)
+ [

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

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

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

## TypeScript Lambda 函数的代码最佳实践
](#typescript-best-practices)

## 设置 TypeScript 项目
<a name="typescript-handler-setup"></a>

使用本地集成式开发环境（IDE）或文本编辑器来编写 TypeScript 函数代码。您无法在 Lambda 控制台上创建 TypeScript 代码。

有多种方法可初始化 TypeScript Lambda 项目。例如，您可以使用 `npm` 创建项目、创建 [AWS SAM 应用程序](typescript-package.md#aws-sam-ts)或创建 [AWS CDK 应用程序](typescript-package.md#aws-cdk-ts)。使用 `npm` 创建项目：

```
npm init
```

您的函数代码存位于 `.ts` 文件中，您在编译时将其转换为 JavaScript 文件。您可以使用 [esbuild](https://esbuild.github.io/) 或 Microsoft 的 TypeScript 编译器（`tsc`）将您的 TypeScript 代码转换为 JavaScript。要使用 esbuild，请将其添加为开发依赖项：

```
npm install -D esbuild
```

典型的 TypeScript Lambda 函数项目遵循以下一般结构：

```
/project-root
  ├── index.ts - Contains main handler
  ├── dist/ - Contains compiled JavaScript
  ├── package.json - Project metadata and dependencies
  ├── package-lock.json - Dependency lock file
  ├── tsconfig.json - TypeScript configuration
  └── node_modules/ - Installed dependencies
```

## 示例 TypeScript Lambda 函数代码
<a name="typescript-example-code"></a>

以下示例 Lambda 函数代码接收有关订单的信息，生成文本文件接收，并将此文件放入 Amazon S3 存储桶中。此示例定义了自定义事件类型（`OrderEvent`）。要了解如何导入 AWS 事件源的类型定义，请参阅 [Lambda 的类型定义](lambda-typescript.md#typescript-type-definitions)。

**注意**  
此示例使用了 ES 模块处理程序。Lambda 同时支持 ES 模块和 CommonJS 处理程序。有关更多信息，请参阅 [CommonJS 和 ES 模块](nodejs-handler.md#nodejs-commonjs-es-modules)。

**Example index.ts Lambda 函数**  

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

// Initialize the S3 client outside the handler for reuse
const s3Client = new S3Client();

// Define the shape of the input event
type OrderEvent = {
    order_id: string;
    amount: number;
    item: string;
}

/**
 * Lambda handler for processing orders and storing receipts in S3.
 */
export const handler = async (event: OrderEvent): Promise<string> => {
    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 instanceof Error ? error.message : 'Unknown error'}`);
        throw error;
    }
};

/**
 * Helper function to upload receipt to S3
 */
async function uploadReceiptToS3(bucketName: string, key: string, receiptContent: string): Promise<void> {
    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 instanceof Error ? error.message : 'Unknown error'}`);
    }
}
```

此 `index.ts` 文件包含以下代码部分：
+ `import` 数据块：使用此数据块来包含 Lambda 函数所需的库，例如 [AWS SDK 客户端](https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/the-request-object.html)。
+ `const s3Client` 声明：用于在处理程序函数之外初始化 [Amazon S3 客户端](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/s3/)。这会导致 Lambda 在[初始化阶段](lambda-runtime-environment.md#runtimes-lifecycle-ib)运行此代码，并保留客户端以供[多次调用时重复使用](lambda-runtime-environment.md#execution-environment-reuse)。
+ `type OrderEvent`：定义预期输入事件的结构。
+ `export const handler`：这是 Lambda 调用的主要处理程序函数。部署函数时，请为[处理程序](https://docs.aws.amazon.com/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="typescript-commonjs-es-modules"></a>

Node.js 支持两个模块系统：CommonJS 和 ECMAScript 模块（ES 模块）。Lambda 建议使用 ES 模块，因为它支持顶层的 await 语句，这使得异步任务能够在[执行环境初始化](#typescript-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 模块。

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

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

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

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

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

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

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

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

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

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

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

1. 选择**保存**。

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

JSON 是 Lambda 函数最常用且最标准的输入格式。在此示例中，该函数需要类似于下方的输入：

```
{
    "order_id": "12345",
    "amount": 199.99,
    "item": "Wireless Headphones"
}
```

在使用 TypeScript Lambda 函数时，您可以使用类型或接口来定义输入事件的形状。在此示例中，我们使用了类型来定义事件结构：

```
type OrderEvent = {
    order_id: string;
    amount: number;
    item: string;
}
```

定义类型或接口后，请在处理程序的签名中用其来确保类型安全性：

```
export const handler = async (event: OrderEvent): Promise<string> => {
```

在编译过程中，TypeScript 会验证事件对象是否包含具有正确类型的必填字段。例如，如果您尝试将 `event.order_id` 用作数字或 `event.amount` 字符串，TypeScript 编译器会报告错误。

## TypeScript 函数的有效处理程序模式
<a name="typescript-handler-signatures"></a>

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

本节中的示例使用了 `S3Event` 类型。但是，您可以使用 [@types/aws-lambda](https://www.npmjs.com/package/@types/aws-lambda) 程序包中的任何其他 AWS 事件类型，也可以定义自有的事件类型。要使用 @types/aws-lambda 中的类型，请执行以下操作：

1. 将 @types/aws-lambda 程序包添加为开发依赖项：

   ```
   npm install -D @types/aws-lambda
   ```

1. 导入所需的类型，例如 `Context`、`S3Event` 或 `Callback`。

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

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

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

```
export const handler = async (event: S3Event): Promise<void> => { };
```

```
export const handler = async (event: S3Event, context: Context): Promise<void> => { };
```

**注意**  
异步处理项目数组时，请务必使用带有 `Promise.all` 的 await 来确保所有操作完成。诸如 `forEach` 这样的方法不会等待异步回调完成。有关更多信息，请参阅 Mozilla 文档中的 [Array.prototype.forEach()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach)。

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

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

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

```
export const handler = (event: S3Event, context: Context): void => { };
```

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

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

```
export const handler = awslambda.streamifyResponse(async (event: APIGatewayProxyEvent, responseStream: NodeJS.WritableStream, context: Context) => { });
```

有关更多信息，请参阅 Lambda 函数的响应流式处理。

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

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

基于回调的函数处理程序可以使用事件、上下文和回调参数。回调参数需要一个 `Error` 和一个响应，该响应必须是 JSON 可序列化的。

以下是回调处理程序模式的有效签名：

```
export const handler = (event: S3Event, context: Context, callback: Callback<void>): void => { };
```

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

**Example 包含回调的 TypeScript 函数**  
以下示例使用了 `APIGatewayProxyCallback`，这是一种特定于 API 网关集成的专用回调类型。大多数 AWS 事件源使用了上述签名中显示的通用 `Callback` 类型。  

```
import { Context, APIGatewayProxyCallback, APIGatewayEvent } from 'aws-lambda';

export const lambdaHandler = (event: APIGatewayEvent, context: Context, callback: APIGatewayProxyCallback): void => {
    console.log(`Event: ${JSON.stringify(event, null, 2)}`);
    console.log(`Context: ${JSON.stringify(context, null, 2)}`);
    callback(null, {
        statusCode: 200,
        body: JSON.stringify({
            message: 'hello world',
        }),
    });
};
```

## 在处理程序中使用适用于 JavaScript v3 的 SDK
<a name="typescript-example-sdk-usage"></a>

通常，您将使用 Lambda 函数与其他 AWS 资源进行交互或对其进行更新。与此类资源最简单的交互方法是使用 适用于 JavaScript 的 AWS SDK。所有支持的 Lambda Node.js 运行时都包含[适用于 JavaScript 版本 3 的 SDK](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/introduction/)。但是，强烈建议您在部署包中包含所需的 AWS SDK 客户端。这样可以最大限度地提高未来 Lambda 运行时更新期间的[向后兼容性](runtimes-update.md#runtime-update-compatibility)。

要向函数添加 SDK 依赖项，请使用适用于所需特定 SDK 客户端的 `npm install` 命令。在示例代码中，我们使用了 [Amazon S3 客户端](https://docs.aws.amazon.com/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.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/s3/)：

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

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

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

## 评估环境变量
<a name="typescript-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="typescript-handler-state"></a>

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

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

## TypeScript Lambda 函数的代码最佳实践
<a name="typescript-best-practices"></a>

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

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

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

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

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

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

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

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

# 使用 .zip 文件归档部署在 Lambda 中转换的 TypeScript 代码
<a name="typescript-package"></a>

在可以将 TypeScript 代码部署到 AWS Lambda 之前，您需要将其转换为 JavaScript。本页介绍了使用 .zip 文件存档构建 TypeScript 代码并将其部署到 Lambda 的三种方法：
+ [使用 AWS Serverless Application Model（AWS SAM）](#aws-sam-ts)
+ [使用 AWS Cloud Development Kit (AWS CDK)](#aws-cdk-ts)
+ [使用 AWS Command Line Interface (AWS CLI) 和 esbuild](#aws-cli-ts)

AWS SAM 和 AWS CDK 可以简化 TypeScript 函数的构建和部署。[AWS SAM 模板规范](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-specification.html)提供了一种简单而干净的语法，用于描述构成无服务器应用程序的 Lambda 函数、API、权限、配置和事件。[AWS CDK](https://docs.aws.amazon.com/cdk/v2/guide/home.html) 使您能够借助编程语言的强大表达能力，在云中构建可靠、可扩展且成本高效的应用程序。AWS CDK 适合中度到高度经验的 AWS 用户。AWS CDK 和 AWS SAM 两者均使用 esbuild 将 TypeScript 代码转换为 JavaScript。

## 使用 AWS SAM 将 TypeScript 代码部署到 Lambda
<a name="aws-sam-ts"></a>

请按照以下步骤使用 AWS SAM 来下载、构建和部署示例 Hello World TypeScript 应用程序。此应用程序实现了基本的 API 后端。它由 Amazon API Gateway 端点和 Lambda 函数组成。在向 API Gateway 端点发送 GET 请求时，会调用 Lambda 函数。该函数将返回一条 `hello world` 消息。

**注意**  
AWS SAM 使用 esbuild 从 TypeScript 代码创建 Node.js Lambda 函数。esbuild 支持目前处于公开预览状态。在公开预览期间，esbuild 支持可能会发生向后不兼容的变更。

**先决条件**

要完成本节中的步骤，您必须满足以下条件：
+ [AWS CLI 版本 2](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)
+ [AWS SAM CLI 版本 1.75 或更高版本](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html)
+ Node.js

**部署示例 AWS SAM 应用程序**

1. 使用 Hello World TypeScript 模板初始化该应用程序。

   ```
   sam init --app-template hello-world-typescript --name sam-app --package-type Zip --runtime nodejs24.x
   ```

1. （可选）该示例应用程序包括常用工具的配置，例如用于代码检查的 [esLlint](https://eslint.org/) 和用于单元测试的 [Jest](https://jestjs.io/)。要运行检查和测试命令，请执行以下操作：

   ```
   cd sam-app/hello-world
   npm install
   npm run lint
   npm run test
   ```

1. 构建应用程序。

   ```
   cd sam-app
   sam build
   ```

1. 部署应用程序。

   ```
   sam deploy --guided
   ```

1. 按照屏幕上的提示操作。要接受交互式体验中提供的原定设置选项，请通过 `Enter` 进行响应。

1. 输出将显示 REST API 的端点。在浏览器中打开该端点，以测试函数。您应该会看到以下响应：

   ```
   {"message":"hello world"}
   ```

1. 这是一个可以通过互联网访问的公有 API 端点。我们建议您在测试后删除该端点。

   ```
   sam delete
   ```

## 使用 AWS CDK 将 TypeScript 代码部署到 Lambda
<a name="aws-cdk-ts"></a>

请按照以下步骤使用 AWS CDK 来构建和部署示例 TypeScript 应用程序。此应用程序实现了基本的 API 后端。它由 API Gateway 端点和 Lambda 函数组成。在向 API Gateway 端点发送 GET 请求时，会调用 Lambda 函数。该函数将返回一条 `hello world` 消息。

**先决条件**

要完成本节中的步骤，您必须满足以下条件：
+ [AWS CLI 版本 2](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)
+ [AWS CDK 版本 2](https://docs.aws.amazon.com/cdk/v2/guide/getting_started.html#getting_started_prerequisites)
+ Node.js
+ [Docker](https://www.docker.com/get-started/) 或 [esbuild](https://esbuild.github.io/)

**部署示例 AWS CDK 应用程序**

1. 为您的新应用程序创建一个项目目录。

   ```
   mkdir hello-world
   cd hello-world
   ```

1. 初始化该应用程序。

   ```
   cdk init app --language typescript
   ```

1. 添加 [@types/aws-lambda](https://www.npmjs.com/package/@types/aws-lambda) 软件包作为开发依赖项。此程序包包含 Lambda 的类型定义。

   ```
   npm install -D @types/aws-lambda
   ```

1. 打开 **lib** 目录。您应该会看到一个名为 **hello-world-stack.ts** 的文件。在此目录中创建两个新文件：**hello-world.function.ts** 和 **hello-world.ts**。

1. 打开 **hello-world.function.ts**，然后将以下代码添加到该文件。这是适用于 Lambda 函数的代码。
**注意**  
`import` 语句从 [@types/aws-lambda](https://www.npmjs.com/package/@types/aws-lambda) 中导入类型定义。它不导入 `aws-lambda` NPM 程序包，这是一个无关的第三方工具。有关更多信息，请参阅 DefinitelyTyped GitHub 存储库中的 [aws-lambda](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/aws-lambda)。

   ```
   import { Context, APIGatewayProxyResult, APIGatewayEvent } from 'aws-lambda';
   
   export const handler = async (event: APIGatewayEvent, context: Context): Promise<APIGatewayProxyResult> => {
       console.log(`Event: ${JSON.stringify(event, null, 2)}`);
       console.log(`Context: ${JSON.stringify(context, null, 2)}`);
       return {
           statusCode: 200,
           body: JSON.stringify({
               message: 'hello world',
           }),
       };
   };
   ```

1. 打开 **hello-world.ts**，然后将以下代码添加到该文件。其中包含 [NodejsFunction 构造](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_lambda_nodejs-readme.html)（它将创建 Lambda 函数）和 [LambdaRestApi 构造](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_apigateway.LambdaRestApi.html)（它将创建 REST API）。

   ```
   import { Construct } from 'constructs';
   import { NodejsFunction } from 'aws-cdk-lib/aws-lambda-nodejs';
   import { LambdaRestApi } from 'aws-cdk-lib/aws-apigateway';
     
   export class HelloWorld extends Construct {
     constructor(scope: Construct, id: string) {
       super(scope, id);
       const helloFunction = new NodejsFunction(this, 'function');
       new LambdaRestApi(this, 'apigw', {
         handler: helloFunction,
       });
     }
   }
   ```

   `NodejsFunction` 构造默认假设以下内容：
   + 您的函数处理程序称为 `handler`。
   + 包含函数代码的 .ts 文件 (**hello-world.function.ts**) 与包含构造的 .ts 文件 (**hello-world.ts**) 位于相同的目录中。该构造使用构造的 ID（“hello-world”）和 Lambda 处理程序文件的名称（“function”）来查找函数代码。例如，如果您的函数代码位于名为 **hello-world.my-function.ts** 的文件中，则 **hello-world.ts** 文件必须按如下所示引用该函数代码：

     ```
     const helloFunction = new NodejsFunction(this, 'my-function');
     ```

   您可以更改此行为并配置其他 esbuild 参数。有关更多信息，请参阅 AWS CDK API 参考中的[配置 esbuild](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_lambda_nodejs-readme.html#configuring-esbuild)。

1. 打开 **hello-world-stack.ts**。这是定义您的 [AWS CDK 堆栈](https://docs.aws.amazon.com/cdk/v2/guide/stacks.html)的代码。使用以下代码替换该代码：

   ```
   import { Stack, StackProps } from 'aws-cdk-lib';
   import { Construct } from 'constructs';
   import { HelloWorld } from './hello-world';
     
   export class HelloWorldStack extends Stack {
     constructor(scope: Construct, id: string, props?: StackProps) {
       super(scope, id, props);
       new HelloWorld(this, 'hello-world');
     }
   }
   ```

1. 从包含您的 `cdk.json` 文件的 `hello-world` 目录中，部署您的应用程序。

   ```
   cdk deploy
   ```

1. AWS CDK 使用 esbuild 构建和打包 Lambda 函数，然后将该函数部署到 Lambda 运行时。输出将显示 REST API 的端点。在浏览器中打开该端点，以测试函数。您应该会看到以下响应：

   ```
   {"message":"hello world"}
   ```

   这是一个可以通过互联网访问的公有 API 端点。我们建议您在测试后删除该端点。

## 使用 AWS CLI 和 esbuild 将 TypeScript 代码部署到 Lambda
<a name="aws-cli-ts"></a>

以下示例演示如何使用 esbuild 和 AWS CLI 转换 TypeScript 代码并将其部署到 Lambda。esbuild 将生成一个包含所有依赖项的 JavaScript 文件。这是您需要添加到 .zip 归档中的唯一文件。

**先决条件**

要完成本节中的步骤，您必须满足以下条件：
+ [AWS CLI 版本 2](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)
+ Node.js
+ Lambda 函数的[执行角色](lambda-intro-execution-role.md)
+ 对于 Windows 用户来说，这是一款压缩文件实用程序，例如 [7zip](https://www.7-zip.org/download.html)。

**部署示例函数**

1. 在本地计算机上，为新函数创建项目目录。

1. 使用 npm 或您选择的软件包管理器创建一个新的 Node.js 项目。

   ```
   npm init
   ```

1. 添加 [@types/aws-lambda](https://www.npmjs.com/package/@types/aws-lambda) 和 [esbuild](https://esbuild.github.io/) 软件包作为开发依赖项。`@types/aws-lambda` 程序包包含 Lambda 的类型定义。

   ```
   npm install -D @types/aws-lambda esbuild
   ```

1. 创建名为 **index.ts** 的新文件。将以下代码添加到该新文件中。这是适用于 Lambda 函数的代码。该函数将返回一条 `hello world` 消息。该函数不会创建任何 API Gateway 资源。
**注意**  
`import` 语句从 [@types/aws-lambda](https://www.npmjs.com/package/@types/aws-lambda) 中导入类型定义。它不导入 `aws-lambda` NPM 程序包，这是一个无关的第三方工具。有关更多信息，请参阅 DefinitelyTyped GitHub 存储库中的 [aws-lambda](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/aws-lambda)。

   ```
   import { Context, APIGatewayProxyResult, APIGatewayEvent } from 'aws-lambda';
   
   export const handler = async (event: APIGatewayEvent, context: Context): Promise<APIGatewayProxyResult> => {
     console.log(`Event: ${JSON.stringify(event, null, 2)}`);
     console.log(`Context: ${JSON.stringify(context, null, 2)}`);
     return {
         statusCode: 200,
         body: JSON.stringify({
             message: 'hello world',
         }),
      };
   };
   ```

1. 将构建脚本添加到 **package.json** 文件。这会将 esbuild 配置为自动创建 .zip 部署软件包。有关更多信息，请参阅 esbuild 文档中的[构建脚本](https://esbuild.github.io/getting-started/#build-scripts)。

------
#### [ Linux and MacOS ]

   ```
   "scripts": {
     "prebuild": "rm -rf dist",
     "build": "esbuild index.ts --bundle --minify --sourcemap --platform=node --target=es2020 --outfile=dist/index.js",
     "postbuild": "cd dist && zip -r index.zip index.js*"
   },
   ```

------
#### [ Windows ]

   在此示例中，`"postbuild"` 命令使用 [7zip](https://www.7-zip.org/download.html) 实用程序创建您的 .zip 文件。使用您自己首选的 Windows zip 实用程序并根据需要修改该命令。

   ```
   "scripts": {
     "prebuild": "del /q dist",
     "build": "esbuild index.ts --bundle --minify --sourcemap --platform=node --target=es2020 --outfile=dist/index.js",
     "postbuild": "cd dist && 7z a -tzip index.zip index.js*"
   },
   ```

------

1. 构建软件包。

   ```
   npm run build
   ```

1. 使用该 .zip 部署软件包创建 Lambda 函数。将突出显示的文本替换为您的[执行角色](lambda-intro-execution-role.md)的 Amazon 资源名称（ARN）。

   ```
   aws lambda create-function --function-name hello-world --runtime "nodejs24.x" --role arn:aws:iam::123456789012:role/lambda-ex --zip-file "fileb://dist/index.zip" --handler index.handler
   ```

1. [运行测试事件](testing-functions.md)，以确认该函数会返回以下响应。如果您想使用 API Gateway 调用此函数，请[创建和配置 REST API](https://docs.aws.amazon.com/apigateway/latest/developerguide/how-to-create-api.html)。

   ```
   {
     "statusCode": 200,
     "body": "{\"message\":\"hello world\"}"
   }
   ```

# 使用容器镜像在 Lambda 中部署转换后的 TypeScript 代码
<a name="typescript-image"></a>

您可以将 TypeScript 代码作为 Node.js [容器镜像](images-create.md)部署到 AWS Lambda 函数中。AWS 将为 Node.js 提供[基本镜像](nodejs-image.md#nodejs-image-base)，以帮助您构建容器镜像。这些基本映像会预加载一个语言运行时和在 Lambda 上运行映像所需的其他组件。AWS 为每个基本映像提供 Dockerfile，以帮助构建容器映像。

如果使用社群或私有企业基本镜像，则必须[将 Node.js 运行时接口客户端 (RIC)](nodejs-image.md#nodejs-image-clients) 添加到该基本镜像，以使其与 Lambda 兼容。

Lambda 提供了可用于本地测试的运行时系统接口仿真器。Node.js 的 AWS 基本映像包含运行时系统接口仿真器。如果您使用备用基本映像，例如 Alpine Linux 或  Debian 映像，则可[将仿真器构建到映像中](https://github.com/aws/aws-lambda-runtime-interface-emulator/?tab=readme-ov-file#build-rie-into-your-base-image)或[将其安装在本地计算机上](https://github.com/aws/aws-lambda-runtime-interface-emulator/?tab=readme-ov-file#test-an-image-without-adding-rie-to-the-image)。

## 使用 Node.js 基本映像构建和打包 TypeScript 函数代码
<a name="base-image-typescript"></a>

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

要完成本节中的步骤，您必须满足以下条件：
+ [AWS CLI 版本 2](https://docs.aws.amazon.com/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 22.x

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

**通过AWS基本映像为 Lambda 创建映像**

1. 在本地计算机上，为新函数创建项目目录。

1. 使用 `npm` 或您选择的软件包管理器创建一个新的 Node.js 项目。

   ```
   npm init
   ```

1. 添加 [@types/aws-lambda](https://www.npmjs.com/package/@types/aws-lambda) 和 [esbuild](https://esbuild.github.io/) 软件包作为开发依赖项。`@types/aws-lambda` 程序包包含 Lambda 的类型定义。

   ```
   npm install -D @types/aws-lambda esbuild
   ```

1. 将[构建脚本](https://esbuild.github.io/getting-started/#build-scripts)添加到 `package.json` 文件。

   ```
     "scripts": {
     "build": "esbuild index.ts --bundle --minify --sourcemap --platform=node --target=es2020 --outfile=dist/index.js"
   }
   ```

1. 创建名为 `index.ts` 的新文件。将以下示例代码添加到该新文件。这是适用于 Lambda 函数的代码。该函数将返回一条 `hello world` 消息。
**注意**  
`import` 语句从 [@types/aws-lambda](https://www.npmjs.com/package/@types/aws-lambda) 中导入类型定义。它不导入 `aws-lambda` NPM 程序包，这是一个无关的第三方工具。有关更多信息，请参阅 DefinitelyTyped GitHub 存储库中的 [aws-lambda](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/aws-lambda)。

   ```
   import { Context, APIGatewayProxyResult, APIGatewayEvent } from 'aws-lambda';
   
   export const handler = async (event: APIGatewayEvent, context: Context): Promise<APIGatewayProxyResult> => {
       console.log(`Event: ${JSON.stringify(event, null, 2)}`);
       console.log(`Context: ${JSON.stringify(context, null, 2)}`);
       return {
           statusCode: 200,
           body: JSON.stringify({
               message: 'hello world',
           }),
       };
   };
   ```

1. 使用以下配置创建一个新的 Dockerfile。
   + 将 `FROM` 属性设置为基本映像的 URI。
   + 设置 `CMD` 参数以指定 Lambda 函数处理程序。

   以下示例 Dockerfile 将使用多阶段构建。第一步将 TypeScript 代码转换为 JavaScript。第二步生成仅包含 JavaScript 文件和生产依赖项的容器映像。

   请注意，示例 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 as builder
   WORKDIR /usr/app
   COPY package.json index.ts  ./
   RUN npm install
   RUN npm run build
       
   FROM public.ecr.aws/lambda/nodejs:22
   WORKDIR ${LAMBDA_TASK_ROOT}
   COPY --from=builder /usr/app/dist/* ./
   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="typescript-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="typescript-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 存储库的 AWS 区域。
   + 将 `111122223333` 替换为您的 AWS 账户 ID。

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

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 us-east-1 --image-scanning-configuration scanOnPush=true --image-tag-mutability MUTABLE
   ```
**注意**  
Amazon ECR 存储库必须与 Lambda 函数位于同一 AWS 区域 内。

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

   ```
   {
       "repository": {
           "repositoryArn": "arn:aws:ecr:us-east-1:111122223333:repository/hello-world",
           "registryId": "111122223333",
           "repositoryName": "hello-world",
           "repositoryUri": "111122223333.dkr.ecr.us-east-1.amazonaws.com/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.us-east-1.amazonaws.com/hello-world:latest
   ```

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

   ```
   docker push 111122223333.dkr.ecr.us-east-1.amazonaws.com/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.us-east-1.amazonaws.com/hello-world:latest \
     --role arn:aws:iam::111122223333:role/lambda-ex
   ```
**注意**  
只要映像与 Lambda 函数位于同一区域内，您就可以使用其他 AWS 账户中的映像创建函数。有关更多信息，请参阅 [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.us-east-1.amazonaws.com/hello-world:latest \
  --publish
```

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

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

要启用上下文对象的类型检查，必须添加 [@types/aws-lambda](https://www.npmjs.com/package/@types/aws-lambda) 程序包作为开发依赖项并导入 `Context` 类型。有关更多信息，请参阅 [Lambda 的类型定义](lambda-typescript.md#typescript-type-definitions)。

**上下文方法**
+ `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.ts 文件**  
以下示例函数记录了上下文信息并返回了日志的位置。  
在 Lambda 函数中使用此代码之前，必须添加 [@types/aws-lambda](https://www.npmjs.com/package/@types/aws-lambda) 程序包作为开发依赖项。此程序包包含 Lambda 的类型定义。有关更多信息，请参阅 [Lambda 的类型定义](lambda-typescript.md#typescript-type-definitions)。

```
import { Context } from 'aws-lambda';
export const lambdaHandler = async (event: string, context: Context): Promise<string> => {
  console.log('Remaining time: ', context.getRemainingTimeInMillis());
  console.log('Function name: ', context.functionName);
  return context.logStreamName;
};
```

# TypeScript Lambda 函数日志记录和监控
<a name="typescript-logging"></a>

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

要从函数代码输出日志，可以使用[控制台对象](https://nodejs.org/docs/latest-v18.x/api/console.html)上的方法。如需更详细的日志记录，可以使用任何写入 `stdout` 或 `stderr` 的日志记录库。

**Topics**
+ [

## 使用日志记录工具和库
](#typescript-tools-libraries)
+ [

## 将 Powertools for AWS Lambda（TypeScript）和 AWS SAM 用于结构化日志记录
](#typescript-logging-sam)
+ [

## 将 Powertools for AWS Lambda（TypeScript）和 AWS CDK 用于结构化日志记录
](#typescript-logging-cdk)
+ [

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

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

## 使用日志记录工具和库
<a name="typescript-tools-libraries"></a>

[Powertools for AWS Lambda（TypeScript）](https://docs.aws.amazon.com/powertools/typescript/)是一个开发人员工具包，可用于实施无服务器最佳实践并提高开发人员速度。[日志记录实用程序](https://docs.powertools.aws.dev/lambda/typescript/latest/features/logger/)提供经优化的 Lambda 日志记录程序，其中包含有关所有函数的函数上下文的附加信息，输出结构为 JSON。请使用该实用程序执行以下操作：
+ 从 Lambda 上下文中捕获关键字段，冷启动并将日志记录输出结构化为 JSON
+ 根据指示记录 Lambda 调用事件（默认情况下禁用）
+ 通过日志采样仅针对一定百分比的调用输出所有日志（默认情况下禁用）
+ 在任何时间点将其他键附加到结构化日志
+ 使用自定义日志格式设置程序（自带格式设置程序），从而在与组织的日志记录 RFC 兼容的结构中输出日志

## 将 Powertools for AWS Lambda（TypeScript）和 AWS SAM 用于结构化日志记录
<a name="typescript-logging-sam"></a>

请按照以下步骤使用 AWS SAM 通过集成的 [Powertools for AWS Lambda（TypeScript）](https://docs.powertools.aws.dev/lambda-typescript)模块来下载、构建和部署示例 Hello World TypeScript 应用程序。此应用程序实现了基本的 API 后端，并使用 Powertools 发送日志、指标和跟踪。它由 Amazon API Gateway 端点和 Lambda 函数组成。在向 API Gateway 端点发送 GET 请求时，Lambda 函数会使用嵌入式指标格式向 CloudWatch 调用、发送日志和指标，并向 AWS X-Ray 发送跟踪。该函数将返回一条 `hello world` 消息。

**先决条件**

要完成本节中的步骤，您必须满足以下条件：
+ Node.js 20 或更高版本
+ [AWS CLI 版本 2](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)
+ [AWS SAM CLI 版本 1.75 或更高版本](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html)。如果您使用的是旧版本的 AWS SAM CLI，请参阅[升级 AWS SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/manage-sam-cli-versions.html#manage-sam-cli-versions-upgrade)。

**部署示例 AWS SAM 应用程序**

1. 使用 Hello World TypeScript 模板初始化该应用程序。

   ```
   sam init --app-template hello-world-powertools-typescript --name sam-app --package-type Zip --runtime nodejs24.x
   ```

1. 构建应用程序。

   ```
   cd sam-app && sam build
   ```

1. 部署应用程序。

   ```
   sam deploy --guided
   ```

1. 按照屏幕上的提示操作。要在交互式体验中接受提供的默认选项，请按 `Enter`。
**注意**  
对于 **HelloWorldFunction 可能没有定义授权，确定执行此操作吗？**，确保输入 `y`。

1. 获取已部署应用程序的 URL：

   ```
   aws cloudformation describe-stacks --stack-name sam-app --query 'Stacks[0].Outputs[?OutputKey==`HelloWorldApi`].OutputValue' --output text
   ```

1. 调用 API 端点：

   ```
   curl <URL_FROM_PREVIOUS_STEP>
   ```

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

   ```
   {"message":"hello world"}
   ```

1. 要获取该函数的日志，请运行 [sam logs](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-cli-command-reference-sam-logs.html)。有关更多信息，请参阅《AWS Serverless Application Model 开发人员指南》中的 [使用日志](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-logging.html)**。

   ```
   sam logs --stack-name sam-app
   ```

   该日志输出类似于以下示例：

   ```
   2025/01/31/[$LATEST]4d53e8d279824834a1ccd35511a4949c 2025-08-31T09:33:10.552000 START RequestId: 70693159-7e94-4102-a2af-98a6343fb8fb Version: $LATEST
   2025/01/31/[$LATEST]4d53e8d279824834a1ccd35511a4949c 2025-08-31T09:33:10.594000 2025-08-31T09:33:10.557Z 70693159-7e94-4102-a2af-98a6343fb8fb INFO {"_aws":{"Timestamp":1661938390556,"CloudWatchMetrics":[{"Namespace":"sam-app","Dimensions":[["service"]],"Metrics":[{"Name":"ColdStart","Unit":"Count"}]}]},"service":"helloWorld","ColdStart":1}
   2025/01/31/[$LATEST]4d53e8d279824834a1ccd35511a4949c 2025-08-31T09:33:10.595000 2025-08-31T09:33:10.595Z 70693159-7e94-4102-a2af-98a6343fb8fb INFO {"level":"INFO","message":"This is an INFO log - sending HTTP 200 - hello world response","service":"helloWorld","timestamp":"2025-08-31T09:33:10.594Z"}
   2025/01/31/[$LATEST]4d53e8d279824834a1ccd35511a4949c 2025-08-31T09:33:10.655000 2025-08-31T09:33:10.655Z 70693159-7e94-4102-a2af-98a6343fb8fb INFO {"_aws":{"Timestamp":1661938390655,"CloudWatchMetrics":[{"Namespace":"sam-app","Dimensions":[["service"]],"Metrics":[]}]},"service":"helloWorld"}
   2025/01/31/[$LATEST]4d53e8d279824834a1ccd35511a4949c 2025-08-31T09:33:10.754000 END RequestId: 70693159-7e94-4102-a2af-98a6343fb8fb
   2025/01/31/[$LATEST]4d53e8d279824834a1ccd35511a4949c 2025-08-31T09:33:10.754000 REPORT RequestId: 70693159-7e94-4102-a2af-98a6343fb8fb Duration: 201.55 ms Billed Duration: 202 ms Memory Size: 128 MB Max Memory Used: 66 MB Init Duration: 252.42 ms
   XRAY TraceId: 1-630f2ad5-1de22b6d29a658a466e7ecf5 SegmentId: 567c116658fbf11a Sampled: true
   ```

1. 这是一个可以通过互联网访问的公有 API 端点。我们建议您在测试后删除该端点。

   ```
   sam delete
   ```

### 管理日志保留日期
<a name="typescript-log-retention"></a>

删除函数时，日志组不会自动删除。要避免无限期存储日志，请删除日志组，或配置一个保留期，在该保留期结束后，日志将自动删除。要设置日志保留日期，请将以下内容添加到您的 AWS SAM 模板中：

```
Resources:
  HelloWorldFunction:
    Type: AWS::Serverless::Function
    Properties:
    # Omitting other properties
  
  LogGroup:
    Type: AWS::Logs::LogGroup
    Properties:
      LogGroupName: !Sub "/aws/lambda/${HelloWorldFunction}"
      RetentionInDays: 7
```

## 将 Powertools for AWS Lambda（TypeScript）和 AWS CDK 用于结构化日志记录
<a name="typescript-logging-cdk"></a>

请按照以下步骤使用 AWS CDK 通过集成的 [Powertools for AWS Lambda（TypeScript）](https://docs.powertools.aws.dev/lambda-typescript)模块来下载、构建和部署示例 Hello World TypeScript 应用程序。此应用程序实现了基本的 API 后端，并使用 Powertools 发送日志、指标和跟踪。它由 Amazon API Gateway 端点和 Lambda 函数组成。在向 API Gateway 端点发送 GET 请求时，Lambda 函数会使用嵌入式指标格式向 CloudWatch 调用、发送日志和指标，并向 AWS X-Ray 发送跟踪。该函数将返回一条 `hello world` 消息。

**先决条件**

要完成本节中的步骤，您必须满足以下条件：
+ Node.js 20 或更高版本
+ [AWS CLI 版本 2](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)
+ [AWS CDK 版本 2](https://docs.aws.amazon.com/cdk/v2/guide/getting_started.html#getting_started_prerequisites)
+ [AWS SAM CLI 版本 1.75 或更高版本](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html)。如果您使用的是旧版本的 AWS SAM CLI，请参阅[升级 AWS SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/manage-sam-cli-versions.html#manage-sam-cli-versions-upgrade)。

**部署示例 AWS CDK 应用程序**

1. 为您的新应用程序创建一个项目目录。

   ```
   mkdir hello-world
   cd hello-world
   ```

1. 初始化该应用程序。

   ```
   cdk init app --language typescript
   ```

1. 添加 [@types/aws-lambda](https://www.npmjs.com/package/@types/aws-lambda) 软件包作为开发依赖项。

   ```
   npm install -D @types/aws-lambda
   ```

1. 安装 Powertools [Logger 实用程序](https://docs.aws.amazon.com/powertools/typescript/latest/features/logger/)。

   ```
   npm install @aws-lambda-powertools/logger
   ```

1. 打开 **lib** 目录。您应该会看到一个名为 **hello-world-stack.ts** 的文件。在此目录中创建两个新文件：**hello-world.function.ts** 和 **hello-world.ts**。

1. 打开 **hello-world.function.ts**，然后将以下代码添加到该文件。这是适用于 Lambda 函数的代码。

   ```
   import { APIGatewayEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
   import { Logger } from '@aws-lambda-powertools/logger';
   const logger = new Logger();
     
   export const handler = async (event: APIGatewayEvent, context: Context): Promise<APIGatewayProxyResult> => {
     logger.info('This is an INFO log - sending HTTP 200 - hello world response');
     return {
       statusCode: 200,
       body: JSON.stringify({
         message: 'hello world',
       }),
     };
   };
   ```

1. 打开 **hello-world.ts**，然后将以下代码添加到该文件。它包含 [NodejsFunction 构造](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_lambda_nodejs-readme.html)，该构造创建 Lambda 函数，为 Powertools 配置环境变量，并将日志保留日期设置为一周。它还包括创建 REST API 的 [LambdaRestApi 构造](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_apigateway.LambdaRestApi.html)。

   ```
   import { Construct } from 'constructs';
   import { NodejsFunction } from 'aws-cdk-lib/aws-lambda-nodejs';
   import { LambdaRestApi } from 'aws-cdk-lib/aws-apigateway';
   import { RetentionDays } from 'aws-cdk-lib/aws-logs';
   import { CfnOutput } from 'aws-cdk-lib';
     
   export class HelloWorld extends Construct {
     constructor(scope: Construct, id: string) {
       super(scope, id);
       const helloFunction = new NodejsFunction(this, 'function', {
         environment: {
           Powertools_SERVICE_NAME: 'helloWorld',
           LOG_LEVEL: 'INFO',
         },
         logRetention: RetentionDays.ONE_WEEK,
       });
       const api = new LambdaRestApi(this, 'apigw', {
         handler: helloFunction,
       });
       new CfnOutput(this, 'apiUrl', {
         exportName: 'apiUrl',
         value: api.url,
       });
     }
   }
   ```

1. 打开 **hello-world-stack.ts**。这是定义您的 [AWS CDK 堆栈](https://docs.aws.amazon.com/cdk/v2/guide/stacks.html)的代码。使用以下代码替换该代码：

   ```
   import { Stack, StackProps } from 'aws-cdk-lib';
   import { Construct } from 'constructs';
   import { HelloWorld } from './hello-world';
       
   export class HelloWorldStack extends Stack {
     constructor(scope: Construct, id: string, props?: StackProps) {
       super(scope, id, props);
       new HelloWorld(this, 'hello-world');
     }
   }
   ```

1. 转回项目目录。

   ```
   cd hello-world
   ```

1. 部署您的应用程序。

   ```
   cdk deploy
   ```

1. 获取已部署应用程序的 URL：

   ```
   aws cloudformation describe-stacks --stack-name HelloWorldStack --query 'Stacks[0].Outputs[?ExportName==`apiUrl`].OutputValue' --output text
   ```

1. 调用 API 端点：

   ```
   curl <URL_FROM_PREVIOUS_STEP>
   ```

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

   ```
   {"message":"hello world"}
   ```

1. 要获取该函数的日志，请运行 [sam logs](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-cli-command-reference-sam-logs.html)。有关更多信息，请参阅《AWS Serverless Application Model 开发人员指南》中的 [使用日志](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-logging.html)**。

   ```
   sam logs --stack-name HelloWorldStack
   ```

   该日志输出类似于以下示例：

   ```
   2025/01/31/[$LATEST]2ca67f180dcd4d3e88b5d68576740c8e 2025-08-31T14:48:37.047000 START RequestId: 19ad1007-ff67-40ce-9afe-0af0a9eb512c Version: $LATEST
   2025/01/31/[$LATEST]2ca67f180dcd4d3e88b5d68576740c8e 2025-08-31T14:48:37.050000 {
   "level": "INFO",
   "message": "This is an INFO log - sending HTTP 200 - hello world response",
   "service": "helloWorld",
   "timestamp": "2025-08-31T14:48:37.048Z",
   "xray_trace_id": "1-630f74c4-2b080cf77680a04f2362bcf2"
   }
   2025/01/31/[$LATEST]2ca67f180dcd4d3e88b5d68576740c8e 2025-08-31T14:48:37.082000 END RequestId: 19ad1007-ff67-40ce-9afe-0af0a9eb512c
   2025/01/31/[$LATEST]2ca67f180dcd4d3e88b5d68576740c8e 2025-08-31T14:48:37.082000 REPORT RequestId: 19ad1007-ff67-40ce-9afe-0af0a9eb512c Duration: 34.60 ms Billed Duration: 35 ms Memory Size: 128 MB Max Memory Used: 57 MB Init Duration: 173.48 ms
   ```

1. 这是一个可以通过互联网访问的公有 API 端点。我们建议您在测试后删除该端点。

   ```
   cdk destroy
   ```

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

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

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

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

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

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

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

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

1. 创建日志流。

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

# 追踪 AWS Lambda 中的 TypeScript 代码
<a name="typescript-tracing"></a>

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

要将跟踪数据发送到 X-Ray，您可以使用以下三个开发工具包库之一：
+ [适用于 OpenTelemetry 的 AWS 发行版 (ADOT)](https://aws.amazon.com/otel) – 一种安全、可供生产、支持 AWS 的 OpenTelemetry (OTel) SDK 的分发版本。
+ [适用于 Node.js 的 AWS X-Ray SDK](https://docs.aws.amazon.com/xray/latest/devguide/xray-sdk-nodejs.html) – 用于生成跟踪数据并将其发送到 X-Ray 的 SDK。
+ [Powertools for AWS Lambda（TypeScript）](https://docs.aws.amazon.com/powertools/typescript/latest/)– 一个开发人员工具包，可用于实施无服务器最佳实践并提高开发人员速度。

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

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

**Topics**
+ [

## 将 Powertools for AWS Lambda（TypeScript）和 AWS SAM 用于跟踪
](#typescript-tracing-sam)
+ [

## 将 Powertools for AWS Lambda（TypeScript）和 AWS CDK 用于跟踪
](#typescript-tracing-cdk)
+ [

## 解释 X-Ray 跟踪
](#typescript-tracing-interpretation)

## 将 Powertools for AWS Lambda（TypeScript）和 AWS SAM 用于跟踪
<a name="typescript-tracing-sam"></a>

请按照以下步骤使用 AWS SAM 通过集成的 [Powertools for AWS Lambda（TypeScript）](https://docs.powertools.aws.dev/lambda-typescript)模块来下载、构建和部署示例 Hello World TypeScript 应用程序。此应用程序实现了基本的 API 后端，并使用 Powertools 发送日志、指标和跟踪。它由 Amazon API Gateway 端点和 Lambda 函数组成。在向 API Gateway 端点发送 GET 请求时，Lambda 函数会使用嵌入式指标格式向 CloudWatch 调用、发送日志和指标，并向 AWS X-Ray 发送跟踪。该函数将返回一条 `hello world` 消息。

**先决条件**

要完成本节中的步骤，您必须满足以下条件：
+ Node.js
+ [AWS CLI 版本 2](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)
+ [AWS SAM CLI 版本 1.75 或更高版本](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html)。如果您使用的是旧版本的 AWS SAM CLI，请参阅[升级 AWS SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/manage-sam-cli-versions.html#manage-sam-cli-versions-upgrade)。

**部署示例 AWS SAM 应用程序**

1. 使用 Hello World TypeScript 模板初始化该应用程序。

   ```
   sam init --app-template hello-world-powertools-typescript --name sam-app --package-type Zip --runtime nodejs24.x --no-tracing
   ```

1. 构建应用程序。

   ```
   cd sam-app && sam build
   ```

1. 部署应用程序。

   ```
   sam deploy --guided
   ```

1. 按照屏幕上的提示操作。要在交互式体验中接受提供的默认选项，请按 `Enter`。
**注意**  
对于 **HelloWorldFunction 可能没有定义授权，确定执行此操作吗？**，确保输入 `y`。

1. 获取已部署应用程序的 URL：

   ```
   aws cloudformation describe-stacks --stack-name sam-app --query 'Stacks[0].Outputs[?OutputKey==`HelloWorldApi`].OutputValue' --output text
   ```

1. 调用 API 端点：

   ```
   curl <URL_FROM_PREVIOUS_STEP>
   ```

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

   ```
   {"message":"hello world"}
   ```

1. 要获取该函数的跟踪信息，请运行 [sam traces](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-cli-command-reference-sam-traces.html)。

   ```
   sam traces
   ```

   该跟踪输出类似于以下示例：

   ```
   XRay Event [revision 1] at (2023-01-31T11:29:40.527000) with id (1-11a2222-111a222222cb33de3b95daf9) and duration (0.483s)
     - 0.425s - sam-app/Prod [HTTP: 200]
       - 0.422s - Lambda [HTTP: 200]
     - 0.406s - sam-app-HelloWorldFunction-Xyzv11a1bcde [HTTP: 200]
     - 0.172s - sam-app-HelloWorldFunction-Xyzv11a1bcde
       - 0.179s - Initialization
       - 0.112s - Invocation
         - 0.052s - ## app.lambdaHandler
           - 0.001s - ### MySubSegment
       - 0.059s - Overhead
   ```

1. 这是一个可以通过互联网访问的公有 API 端点。我们建议您在测试后删除该端点。

   ```
   sam delete
   ```

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

## 将 Powertools for AWS Lambda（TypeScript）和 AWS CDK 用于跟踪
<a name="typescript-tracing-cdk"></a>

请按照以下步骤使用 AWS CDK 通过集成的 [Powertools for AWS Lambda（TypeScript）](https://docs.powertools.aws.dev/lambda-typescript)模块来下载、构建和部署示例 Hello World TypeScript 应用程序。此应用程序实现了基本的 API 后端，并使用 Powertools 发送日志、指标和跟踪。它由 Amazon API Gateway 端点和 Lambda 函数组成。在向 API Gateway 端点发送 GET 请求时，Lambda 函数会使用嵌入式指标格式向 CloudWatch 调用、发送日志和指标，并向 AWS X-Ray 发送跟踪。该函数将返回一条 `hello world` 消息。

**先决条件**

要完成本节中的步骤，您必须满足以下条件：
+ Node.js
+ [AWS CLI 版本 2](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)
+ [AWS CDK 版本 2](https://docs.aws.amazon.com/cdk/v2/guide/getting_started.html#getting_started_prerequisites)
+ [AWS SAM CLI 版本 1.75 或更高版本](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html)。如果您使用的是旧版本的 AWS SAM CLI，请参阅[升级 AWS SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/manage-sam-cli-versions.html#manage-sam-cli-versions-upgrade)。

**部署示例 AWS Cloud Development Kit (AWS CDK) 应用程序**

1. 为您的新应用程序创建一个项目目录。

   ```
   mkdir hello-world
   cd hello-world
   ```

1. 初始化该应用程序。

   ```
   cdk init app --language typescript
   ```

1. 添加 [@types/aws-lambda](https://www.npmjs.com/package/@types/aws-lambda) 软件包作为开发依赖项。

   ```
   npm install -D @types/aws-lambda
   ```

1. 安装 Powertools [Tracer 实用程序](https://docs.aws.amazon.com/powertools/typescript/latest/features/tracer/)。

   ```
   npm install @aws-lambda-powertools/tracer
   ```

1. 打开 **lib** 目录。您应该会看到一个名为 **hello-world-stack.ts** 的文件。在此目录中创建两个新文件：**hello-world.function.ts** 和 **hello-world.ts**。

1. 打开 **hello-world.function.ts**，然后将以下代码添加到该文件。这是适用于 Lambda 函数的代码。

   ```
   import { APIGatewayEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
   import { Tracer } from '@aws-lambda-powertools/tracer';
   const tracer = new Tracer();
   
   export const handler = async (event: APIGatewayEvent, context: Context): Promise<APIGatewayProxyResult> => {
     // Get facade segment created by Lambda
     const segment = tracer.getSegment();
   
     // Create subsegment for the function and set it as active
     const handlerSegment = segment.addNewSubsegment(`## ${process.env._HANDLER}`);
     tracer.setSegment(handlerSegment);
   
     // Annotate the subsegment with the cold start and serviceName
     tracer.annotateColdStart();
     tracer.addServiceNameAnnotation();
   
     // Add annotation for the awsRequestId
     tracer.putAnnotation('awsRequestId', context.awsRequestId);
     // Create another subsegment and set it as active
     const subsegment = handlerSegment.addNewSubsegment('### MySubSegment');
     tracer.setSegment(subsegment);
     let response: APIGatewayProxyResult = {
       statusCode: 200,
       body: JSON.stringify({
         message: 'hello world',
       }),
     };
     // Close subsegments (the Lambda one is closed automatically)
     subsegment.close(); // (### MySubSegment)
     handlerSegment.close(); // (## index.handler)
   
     // Set the facade segment as active again (the one created by Lambda)
     tracer.setSegment(segment);
     return response;
   };
   ```

1. 打开 **hello-world.ts**，然后将以下代码添加到该文件。它包含 [NodejsFunction 构造](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_lambda_nodejs-readme.html)，该构造创建 Lambda 函数，为 Powertools 配置环境变量，并将日志保留日期设置为一周。它还包括创建 REST API 的 [LambdaRestApi 构造](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_apigateway.LambdaRestApi.html)。

   ```
   import { Construct } from 'constructs';
   import { NodejsFunction } from 'aws-cdk-lib/aws-lambda-nodejs';
   import { LambdaRestApi } from 'aws-cdk-lib/aws-apigateway';
   import { CfnOutput } from 'aws-cdk-lib';
   import { Tracing } from 'aws-cdk-lib/aws-lambda';
   
   export class HelloWorld extends Construct {
     constructor(scope: Construct, id: string) {
       super(scope, id);
       const helloFunction = new NodejsFunction(this, 'function', {
         environment: {
           POWERTOOLS_SERVICE_NAME: 'helloWorld',
         },
         tracing: Tracing.ACTIVE,
       });
       const api = new LambdaRestApi(this, 'apigw', {
         handler: helloFunction,
       });
       new CfnOutput(this, 'apiUrl', {
         exportName: 'apiUrl',
         value: api.url,
       });
     }
   }
   ```

1. 打开 **hello-world-stack.ts**。这是定义您的 [AWS CDK 堆栈](https://docs.aws.amazon.com/cdk/v2/guide/stacks.html)的代码。使用以下代码替换该代码：

   ```
   import { Stack, StackProps } from 'aws-cdk-lib';
   import { Construct } from 'constructs';
   import { HelloWorld } from './hello-world';
     
   export class HelloWorldStack extends Stack {
     constructor(scope: Construct, id: string, props?: StackProps) {
       super(scope, id, props);
       new HelloWorld(this, 'hello-world');
     }
   }
   ```

1. 部署您的应用程序。

   ```
   cd ..
   cdk deploy
   ```

1. 获取已部署应用程序的 URL：

   ```
   aws cloudformation describe-stacks --stack-name HelloWorldStack --query 'Stacks[0].Outputs[?ExportName==`apiUrl`].OutputValue' --output text
   ```

1. 调用 API 端点：

   ```
   curl <URL_FROM_PREVIOUS_STEP>
   ```

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

   ```
   {"message":"hello world"}
   ```

1. 要获取该函数的跟踪信息，请运行 [sam traces](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-cli-command-reference-sam-traces.html)。

   ```
   sam traces
   ```

   该跟踪输出类似于以下示例：

   ```
   XRay Event [revision 1] at (2023-01-31T11:50:06.997000) with id (1-11a2222-111a222222cb33de3b95daf9) and duration (0.449s)
     - 0.350s - HelloWorldStack-helloworldfunction111A2BCD-Xyzv11a1bcde [HTTP: 200]
     - 0.157s - HelloWorldStack-helloworldfunction111A2BCD-Xyzv11a1bcde
       - 0.169s - Initialization
       - 0.058s - Invocation
         - 0.055s - ## index.handler
           - 0.000s - ### MySubSegment
       - 0.099s - Overhead
   ```

1. 这是一个可以通过互联网访问的公有 API 端点。我们建议您在测试后删除该端点。

   ```
   cdk destroy
   ```

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

在配置活跃跟踪后，您可以通过应用程序观察特定请求。[X-Ray 跟踪图](https://docs.aws.amazon.com/xray/latest/devguide/xray-console-servicemap.html)将显示有关应用程序及其所有组件的信息。以下示例显示了一个示例应用程序的跟踪：

![\[\]](http://docs.aws.amazon.com/zh_cn/lambda/latest/dg/images/sample-typescript-servicemap.png)
