

# Lambda 函数的响应流
<a name="configuration-response-streaming"></a>

Lambda 函数可以通过 [Lambda 函数 URL](urls-configuration.md) 或使用 [InvokeWithResponseStream](https://docs.aws.amazon.com/lambda/latest/api/API_InvokeWithResponseStream.html) API（通过 AWS SDK 或直接调用 API），将响应有效载荷在本机流式传输回客户端。您的 Lambda 函数还可以通过 [Amazon API Gateway 代理集成](https://docs.aws.amazon.com/apigateway/latest/developerguide/response-transfer-mode-lambda.html)流式处理响应有效载荷，该集成使用 [InvokeWithResponseStream](https://docs.aws.amazon.com/lambda/latest/api/API_InvokeWithResponseStream.html) API 来调用您的函数。响应流式处理可通过提高首字节时间（TTFB）性能，使延迟敏感型应用程序受益。这是因为您可以在部分响应可用时将其发送回客户端。此外，响应流式传输函数最多可以返回 200MB 的有效载荷，而缓冲响应的最大有效载荷为 6 MB。流式处理响应还意味着您的函数不需要在内存中容纳整个响应。对于非常大的响应，这样可以减少您需要为函数配置的内存量。

**注意**  
Lambda 响应流式处理在所有 AWS 区域中均不可用。请参阅 Builder Center 的 [按区域划分的 AWS 功能](https://builder.aws.com/build/capabilities)，了解按区域划分的特征可用性。

Lambda 流式处理您的响应的速度取决于响应大小。函数响应的前 6MB 的流式处理速率无上限。对于大于 6MB 的响应，响应的其余部分受带宽上限的限制。有关流式处理带宽的详细信息，请参阅[响应流式处理的带宽限制](#config-rs-bandwidth-cap)。

当调用的客户端连接中断时，流式处理响应会产生成本，并且流式处理的响应不会中断或停止。将按整个函数运行的完整时长来向客户收取费用，因此客户在设置过长的函数超时时间时应谨慎行事。

Lambda 在 Node.js 托管式运行时系统上支持响应流式处理。对于包括 Python 在内的其他语言，您也可以[使用带有自定义运行时系统 API 集成的自定义运行时系统](runtimes-custom.md#runtimes-custom-response-streaming)来流式处理响应或使用 [Lambda Web Adapter](https://github.com/awslabs/aws-lambda-web-adapter)。

**注意**  
通过 Lambda 控制台测试函数时，将始终显示缓冲响应。

**Topics**
+ [响应流式处理的带宽限制](#config-rs-bandwidth-cap)
+ [VPC 与响应流的兼容性](#config-rs-vpc-compatibility)
+ [编写支持响应流式处理的 Lambda 函数](config-rs-write-functions.md)
+ [使用 Lambda 函数 URL 调用支持响应流式处理的函数](config-rs-invoke-furls.md)
+ [教程：使用函数 URL 创建响应流式处理 Lambda 函数](response-streaming-tutorial.md)

## 响应流式处理的带宽限制
<a name="config-rs-bandwidth-cap"></a>

函数响应有效载荷的前 6MB 的带宽无上限。在此初始突增之后，Lambda 会以最大 2MBps 的速率流式处理您的响应。如果您的函数响应从未超出 6MB，则此带宽限制永远不适用。

**注意**  
带宽限制仅适用于您的函数的响应负载，不适用于您的函数的网络访问。

无上限带宽的速率因多种因素而异，其中包括函数的处理速度。通常，函数响应的前 6MB 的速率高于 2MBps。如果您的函数将响应流式处理到 AWS 以外的目标，则流式处理速率还取决于外部互联网连接的速度。

## VPC 与响应流的兼容性
<a name="config-rs-vpc-compatibility"></a>

在 VPC 环境中使用 Lambda 函数时，响应流有一些重要注意事项：
+ Lambda 函数 URL 不支持 VPC 环境内的响应流。
+ 您可以使用 `InvokeWithResponseStream` API 通过 AWS SDK 调用 Lambda 函数来在 VPC 中使用响应流。这需要为 Lambda 设置适当的 VPC 端点。
+ 对于 VPC 环境，您需要为 Lambda 创建一个接口 VPC 端点，以实现 VPC 中的资源与 Lambda 服务之间的通信。

VPC 中响应流的典型架构可能包括：

```
Client in VPC -> Interface VPC endpoint for Lambda -> Lambda function -> Response streaming back through the same path
```

# 编写支持响应流式处理的 Lambda 函数
<a name="config-rs-write-functions"></a>

为响应流式处理函数编写处理程序不同于典型的处理程序模式。编写流式处理函数时，请确保执行以下操作：
+ 使用 `awslambda.streamifyResponse()` 装饰器包装您的函数。`awslambda` 全局对象由 Lambda 的 Node.js 运行时环境提供。
+ 正常结束流，以确保所有数据处理完成。

## 配置处理程序函数以流式处理响应
<a name="config-rs-write-functions-handler"></a>

要向运行时系统指示 Lambda 应该流式处理函数的响应，您必须使用 `streamifyResponse()` 装饰器包装函数。从而指示运行时系统使用正确的响应流式处理逻辑路径，同时确保函数能够流式处理响应。

`streamifyResponse()` 装饰器接受可接受以下参数的函数：
+ `event` – 提供有关函数 URL 的调用事件的信息，例如 HTTP 方法、查询参数和请求正文。
+ `responseStream` – 提供可写流。
+ `context` – 提供的方法和属性包含有关调用、函数和执行环境的信息。

`responseStream` 对象为 [Node.js `writableStream`](https://nodesource.com/blog/understanding-streams-in-nodejs/)。与任何此类流一样，您应该使用 `pipeline()` 方法。

**注意**  
`awslambda` 全局对象由 Lambda 的 Node.js 运行时自动提供，无需导入。

**Example 支持响应流式处理的处理程序**  

```
import { pipeline } from 'node:stream/promises';
import { Readable } from 'node:stream';

export const echo = awslambda.streamifyResponse(async (event, responseStream, _context) => {
  // As an example, convert event to a readable stream.
  const requestStream = Readable.from(Buffer.from(JSON.stringify(event)));

  await pipeline(requestStream, responseStream);
});
```

尽管 `responseStream` 提供了写入流的 `write()` 方法，但建议您尽可能使用 [https://nodejs.org/api/stream.html#streampipelinesource-transforms-destination-callback](https://nodejs.org/api/stream.html#streampipelinesource-transforms-destination-callback)。使用 `pipeline()` 能够确保可写流不会被速度更快的可读流所淹没。

## 结束流
<a name="config-rs-write-functions-end"></a>

确保在处理程序返回之前正确结束流。`pipeline()` 方法会自动处理此问题。

对于其他使用案例，请调用 `responseStream.end()` 方法以正确结束流。此方法表示不应向流写入更多数据。如果您使用 `pipeline()` 或 `pipe()` 写入流，则不需要使用此方法。

从 Node.js 24 开始，在您的处理程序返回或响应流结束后，Lambda 不再等待未解决的 Promise 完成。如果您的函数依赖于其他异步操作，例如计时器或获取，则应在处理程序中 `await` 它们。

**Example 使用 pipeline() 结束流的示例**  

```
import { pipeline } from 'node:stream/promises';

export const handler = awslambda.streamifyResponse(async (event, responseStream, _context) => {
  await pipeline(requestStream, responseStream);
});
```

**Example 不使用 pipeline() 结束流的示例**  

```
export const handler = awslambda.streamifyResponse(async (event, responseStream, _context) => {
  responseStream.write("Hello ");
  responseStream.write("world ");
  responseStream.write("from ");
  responseStream.write("Lambda!");
  responseStream.end();
});
```

# 使用 Lambda 函数 URL 调用支持响应流式处理的函数
<a name="config-rs-invoke-furls"></a>

**注意**  
您的 Lambda 函数现在可以通过 [Amazon API Gateway 代理集成](https://docs.aws.amazon.com/apigateway/latest/developerguide/response-transfer-mode-lambda.html)流式传输响应有效载荷。

您可以通过更改函数 URL 的调用模式来调用支持响应流式处理的函数。调用模式决定 Lambda 使用哪个 API 操作来调用函数。可用的调用模式有：
+ `BUFFERED` – 这是默认选项。Lambda 通过 `Invoke` API 操作调用函数。负载完成后，调用结果可用。最大负载大小为 6MB。
+ `RESPONSE_STREAM` – 使函数能够在负载结果可用时对其进行流式处理。Lambda 通过 `InvokeWithResponseStream` API 操作调用函数。最大响应有效载荷为 200MB。

通过直接调用 `Invoke` API 操作，您仍然可以在不进行响应流式处理的情况下调用函数。但是，Lambda 会流式处理通过函数 URL 发出的调用的所有响应负载，直到您将调用模式更改为 `BUFFERED`。

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

**设置函数 URL 的调用模式（控制台）**

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

1. 选择您要为其设置调用模式的函数的名称。

1. 选择 **Configuration**（配置）选项卡，然后选择 **Function URL**（函数 URL）。

1. 选择**编辑**，然后选择**其他设置**。

1. 在**调用模式**下，选择所需的调用模式。

1. 选择**保存**。

------
#### [ AWS CLI ]

**设置函数 URL 的调用模式（AWS CLI）**

```
aws lambda update-function-url-config \
  --function-name my-function \
  --invoke-mode RESPONSE_STREAM
```

------
#### [ CloudFormation ]

**设置函数 URL 的调用模式（CloudFormation）**

```
MyFunctionUrl:
  Type: AWS::Lambda::Url
  Properties:
    AuthType: AWS_IAM
    InvokeMode: RESPONSE_STREAM
```

------

有关配置函数 URL 的更多信息，请参阅 [Lambda 函数 URL](urls-configuration.md)。

# 教程：使用函数 URL 创建响应流式处理 Lambda 函数
<a name="response-streaming-tutorial"></a>

在本教程中，您将创建一个 Lambda 函数，该函数定义为 .zip 文件存档，其函数 URL 端点会返回响应流。有关配置函数 URL 的更多信息，请参阅 [函数 URL](urls-configuration.md)。

## 先决条件
<a name="response-streaming-prepare"></a>

本教程假设您对 Lambda 基本操作和 Lambda 控制台有一定了解。如果您还没有了解，请按照 [使用控制台创建 Lambda 函数](getting-started.md#getting-started-create-function) 中的说明创建您的第一个 Lambda 函数。

要完成以下步骤，您需要 [AWS CLI 版本 2](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)。在单独的数据块中列出了命令和预期输出：

```
aws --version
```

您应看到以下输出：

```
aws-cli/2.13.27 Python/3.11.6 Linux/4.14.328-248.540.amzn2.x86_64 exe/x86_64.amzn.2
```

对于长命令，使用转义字符 (`\`) 将命令拆分为多行。

在 Linux 和 macOS 中，可使用您首选的 shell 和程序包管理器。

**注意**  
在 Windows 中，操作系统的内置终端不支持您经常与 Lambda 一起使用的某些 Bash CLI 命令（例如 `zip`）。[安装 Windows Subsystem for Linux](https://docs.microsoft.com/en-us/windows/wsl/install-win10)，获取 Ubuntu 和 Bash 与 Windows 集成的版本。本指南中的示例 CLI 命令使用 Linux 格式。如果您使用的是 Windows CLI，则必须重新格式化包含内联 JSON 文档的命令。

## 创建执行角色
<a name="response-streaming-create-iam-role"></a>

创建[执行角色](lambda-intro-execution-role.md)，向您的 Lambda 函数授予访问AWS资源的权限。

**创建执行角色**

1. 打开 AWS Identity and Access Management（IAM）控制台的 [Roles](https://console.aws.amazon.com/iam/home#/roles)（角色）页面。

1. 选择**创建角色**。

1. 创建具有以下属性的角色：
   + **可信实体类型** – **AWS 服务**
   + **使用场景** – **Lambda**
   + **权限** – **AWSLambdaBasicExecutionRole**
   + **Role name**（角色名称）– **response-streaming-role**

**AWSLambdaBasicExecutionRole** 策略具有函数将日志写入 Amazon CloudWatch Logs 所需的权限。创建角色后，记下其 Amazon 资源名称（ARN）。下一步中需要使用该值。

## 创建响应流式处理函数（AWS CLI）
<a name="response-streaming-tutorial-create-function-cli"></a>

使用 AWS Command Line Interface（AWS CLI）创建具有函数 URL 端点的响应流式处理 Lambda 函数。

**创建能够流式处理响应的函数**

1. 将以下代码示例复制到名为 `index.js` 的文件中。此函数流式传输三个间隔为 1 秒的响应。

   ```
   exports.handler = awslambda.streamifyResponse(
   	async (event, responseStream, _context) => {
   		// Metadata is a JSON serializable JS object. Its shape is not defined here.
   		const metadata = {
   		statusCode: 200,
   		headers: {
   			"Content-Type": "application/json",
   			"CustomHeader": "outerspace"
   		}
   		};
   	
   		// Assign to the responseStream parameter to prevent accidental reuse of the non-wrapped stream.
   		responseStream = awslambda.HttpResponseStream.from(responseStream, metadata);
   	
   		responseStream.write("Streaming with Helper \n");
   		await new Promise(r => setTimeout(r, 1000));
   		responseStream.write("Hello 0 \n");
   		await new Promise(r => setTimeout(r, 1000));
   		responseStream.write("Hello 1 \n");
   		await new Promise(r => setTimeout(r, 1000));
   		responseStream.write("Hello 2 \n");
   		await new Promise(r => setTimeout(r, 1000));
   		responseStream.end();
   		await responseStream.finished();
   	}
     );
   ```

1. 创建部署程序包。

   ```
   zip function.zip index.js
   ```

1. 使用 `create-function` 命令创建 Lambda 函数。将 `--role` 的值替换为上一步中的角色 ARN。此命令将函数超时设置为 10 秒，这样函数就可以流式传输三个响应。

   ```
   aws lambda create-function \
     --function-name my-streaming-function \
     --runtime nodejs24.x \
     --zip-file fileb://function.zip \
     --handler index.handler \
     --timeout 10 \
     --role arn:aws:iam::123456789012:role/response-streaming-role
   ```

**创建函数 URL**

1. 向函数添加基于资源的策略，授予 `lambda:InvokeFunctionUrl` 和 `lambda:InvokeFunction` 权限。每条语句都必须添加到单独的命令中。将 `--principal` 的值替换为您的 AWS 账户 ID。

   ```
   aws lambda add-permission \
     --function-name my-streaming-function \
     --action lambda:InvokeFunctionUrl \
     --statement-id UrlPolicyInvokeURL \
     --principal 123456789012 \
     --function-url-auth-type AWS_IAM
   ```

   ```
   aws lambda add-permission \
       --function-name my-streaming-function \
       --action lambda:InvokeFunction \
       --statement-id UrlPolicyInvokeFunction \
       --principal 123456789012
   ```

1. 使用 `create-function-url-config` 命令为函数创建 URL 端点。

   ```
   aws lambda create-function-url-config \
     --function-name my-streaming-function \
     --auth-type AWS_IAM \
     --invoke-mode RESPONSE_STREAM
   ```
**注意**  
如果收到 `--invoke-mode` 错误，可能需要升级到[新版 AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)。

## 测试函数 URL 端点
<a name="response-streaming-tutorial-test"></a>

通过调用函数来测试集成。您可以在浏览器中打开函数的 URL，也可以使用 curl。

```
curl --request GET "https://abcdefghijklm7nop7qrs740abcd.lambda-url.us-east-1.on.aws/" --user "AKIAIOSFODNN7EXAMPLE" --aws-sigv4 "aws:amz:us-east-1:lambda" --no-buffer
```

我们的函数 URL 使用 `IAM_AUTH` 身份验证类型。这意味着您必须使用 [AWS 访问密钥和私有密钥才能签署请求](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_access-keys.html)。在上一条命令中，将 `AKIAIOSFODNN7EXAMPLE` 替换为 AWS 访问密钥 ID。请在出现提示时输入 AWS 私有密钥。如果没有 AWS 私有密钥，可以改为[使用临时 AWS 凭证](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html)。

应出现如下响应：

```
Streaming with Helper 
Hello 0 
Hello 1
Hello 2
```

## 清除资源
<a name="cleanup"></a>

除非您想要保留为本教程创建的资源，否则可立即将其删除。通过删除您不再使用的 AWS 资源，可防止您的 AWS 账户 产生不必要的费用。

**删除执行角色**

1. 打开 IAM 控制台的[角色页面](https://console.aws.amazon.com/iam/home#/roles)。

1. 选择您创建的执行角色。

1. 选择**删除**。

1. 在文本输入字段中输入角色名称，然后选择**删除**。

**删除 Lambda 函数**

1. 打开 Lamba 控制台的 [Functions（函数）页面](https://console.aws.amazon.com/lambda/home#/functions)。

1. 选择您创建的函数。

1. 依次选择**操作**和**删除**。

1. 在文本输入字段中键入 **confirm**，然后选择 **Delete**（删除）。