

# 在 API Gateway 中设置采用有效载荷响应流式传输的 Lambda 代理集成
<a name="response-transfer-mode-lambda"></a>

您可以流式传输 Lambda 函数的响应，以缩短首字节时间（TTFB），并在部分响应可用时立即将其发送给客户端。API Gateway 要求您使用 [InvokeWithResponseStream](https://docs.aws.amazon.com/lambda/latest/api/API_InvokeWithResponseStream.html) Lambda API 来调用 Lambda 函数。API Gateway 会向 Lambda 函数传递一个事件对象。后端 Lambda 函数会对传入请求数据进行解析，以确定要返回的响应。为了让 API Gateway 能够流式传输 Lambda 输出，Lambda 函数必须按照 API Gateway 要求的[格式](#response-transfer-mode-lambda-format)输出。

## 流和缓冲响应传输模式下 Lambda 代理集成的差异
<a name="response-transfer-mode-lambda-comparison"></a>

以下列表描述了 Lambda 代理集成与用于响应流式传输的 Lambda 代理集成之间的差异：
+ API Gateway 使用 [InvokeWithResponseStream](https://docs.aws.amazon.com/lambda/latest/api/API_InvokeWithResponseStream.html) API 调用用于响应流式处理的 Lambda 代理集成。这会生成不同的 URI，具体如下所示：

  ```
  arn:aws:apigateway:us-west-1:lambda:path/2021-11-15/functions/arn:aws:lambda:us-west-1:111122223333:function:my-function-name/response-streaming-invocations
  ```

  与 Lambda 代理集成相比，此 ARN 对 API 版本使用不同的日期和不同的服务操作。

  如果您使用 API Gateway 控制台进行响应流式传输，则控制台会自动为您使用正确的 URI。
+ 在 Lambda 代理集成中，API Gateway 仅在收到 Lambda 的完整响应后才会将响应发送给客户端。在用于响应流式传输的 Lambda 代理集成中，API Gateway 在收到 Lambda 的有效元数据和分隔符后即开始有效载荷流式传输。
+ 用于响应流式传输的 Lambda 代理集成使用与普通代理集成相同的输入格式，但要求不同的输出格式。

## 用于响应流式传输的 Lambda 代理集成格式
<a name="response-transfer-mode-lambda-format"></a>

当 API Gateway 调用具有响应流式传输功能的 Lambda 函数时，输入格式与代理集成的 Lambda 函数输入格式相同。有关更多信息，请参阅 [用于代理集成的 Lambda 函数的输入格式](set-up-lambda-proxy-integrations.md#api-gateway-simple-proxy-for-lambda-input-format)。

当 Lambda 向 API Gateway 流式传输响应时，响应必须遵循以下格式。该格式使用分隔符分隔元数据 JSON 和原始有效载荷。在这种情况下，有效载荷数据会按照流式 Lambda 函数传输的方式进行流式传输：

```
{
  "headers": {"headerName": "headerValue", ...},
  "multiValueHeaders": { "headerName": ["headerValue", "headerValue2", ...], ... },
  "cookies" : ["cookie1", "cookie2"],
  "statusCode": httpStatusCode
}<DELIMITER>PAYLOAD1 | PAYLOAD2 | PAYLOAD3
```

在输出中：
+ 如果不返回任何额外的响应标头，则可以不指定 `headers`、`multiValueHeaders`、`cookies` 和 `statusCode` 键。
+ `headers` 密钥只能包含单值标头。
+ 输出要求标头中包含 `Transfer-Encoding: chunked` 或 `Content-length: number`。如果您的函数未返回这两个标头中的任何一个，API Gateway 会在响应标头中添加 `Transfer-Encoding: chunked`。
+ `multiValueHeaders` 密钥可以包含多值标头以及单值标头。您可以使用 `multiValueHeaders` 密钥来指定所有额外的标头，包括任何单值标头。
+ 如果您指定 `headers` 和 `multiValueHeaders` 的值，API Gateway 会将它们合并为一个列表。如果两者都指定了相同的键/值对，则合并列表中只会出现 `multiValueHeaders` 的值。
+ 元数据必须是有效的 JSON 格式。仅支持 `headers`、`multiValueHeaders`、`cookies` 和 `statusCode` 键。
+ 必须在元数据 JSON 后面提供一个分隔符。该分隔符必须是 8 个空字节，且必须出现在流数据的前 16 KB 内。
+ API Gateway 对方法响应有效载荷没有特定格式要求。

如果您使用函数 URL 流式传输 Lambda 函数，必须修改 Lambda 函数的输入和输出以满足这些要求。

如果您的 Lambda 函数输出不符合此格式要求，API Gateway 仍可能调用您的 Lambda 函数，但会返回错误。下表展示了 API Gateway 支持的 API 集成请求设置与 Lambda 函数代码的组合。这包括响应传输模式为缓冲时支持的组合。


| 响应传输模式 | 函数代码符合要求的格式 | Lambda 调用 API | API Gateway 是否支持 | 
| --- | --- | --- | --- | 
|  流  |  是  |   [InvokeWithResponseStream](https://docs.aws.amazon.com/lambda/latest/api/API_InvokeWithResponseStream.html)  |  可以。API Gateway 流式传输您的响应。  | 
|  流  |  否  |   [InvokeWithResponseStream](https://docs.aws.amazon.com/lambda/latest/api/API_InvokeWithResponseStream.html)  |  否。API Gateway 调用您的 Lambda 函数并返回 500 错误响应。  | 
|  流  |  是  |   [调用](https://docs.aws.amazon.com/lambda/latest/api/API_Invoke.html)  |  否。API Gateway 不支持此集成配置。  | 
|  流  |  否  |   [调用](https://docs.aws.amazon.com/lambda/latest/api/API_Invoke.html)  |  否。API Gateway 不支持此集成配置。  | 
|  缓冲  |  是  |   [InvokeWithResponseStream](https://docs.aws.amazon.com/lambda/latest/api/API_InvokeWithResponseStream.html)  |  否。API Gateway 不支持此集成配置。  | 
|  缓冲  |  否  |   [InvokeWithResponseStream](https://docs.aws.amazon.com/lambda/latest/api/API_InvokeWithResponseStream.html)  |  否。API Gateway 不支持此集成配置。  | 
|  缓冲  |  是  |   [调用](https://docs.aws.amazon.com/lambda/latest/api/API_Invoke.html)  |  API Gateway 返回 HTTP 标头和状态码，但不返回响应正文。  | 
|  缓冲  |  否  |   [调用](https://docs.aws.amazon.com/lambda/latest/api/API_Invoke.html)  |  可以。这是 Lambda 代理集成。有关更多信息，请参阅 [Lambda 代理集成](set-up-lambda-proxy-integrations.md)。  | 

# 在 API Gateway 中配置采用有效载荷响应流式传输的 Lambda 代理集成
<a name="response-streaming-lambda-configure"></a>

在设置响应有效载荷流式传输时，您可以在资源的集成请求中指定传输模式。通过在集成请求中配置这些设置，可以控制 API Gateway 在集成响应之前和期间的行为。

## 用于响应流式传输的 Lambda 函数示例
<a name="response-streaming-lambda-example"></a>

您的 Lambda 函数必须遵循[用于响应流式传输的 Lambda 代理集成格式](response-transfer-mode-lambda.md#response-transfer-mode-lambda-format)。建议您使用三个示例 Lambda 函数之一来测试响应流式传输。创建 Lambda 函数时，请确保执行以下操作：
+ 为您的函数提供足够的超时时间。建议您将超时设置为至少 1 分钟，以了解响应流式传输。创建生产资源时，请确保您的 Lambda 函数超时涵盖整个请求周期。有关更多信息，请参阅[配置 Lambda 函数超时](https://docs.aws.amazon.com/lambda/latest/dg/configuration-timeout.html)。
+ 使用最新的 Node.js 运行时。
+ 使用已提供 Lambda 响应流式传输的区域。

------
#### [ Using HttpResponseStream.from ]

以下代码示例通过 `awslambda.HttpResponseStream()` 方法（不使用 pipeline 方法）将 JSON 元数据对象和有效载荷流式传输回客户端，您无需创建分隔符。有关更多信息，请参阅[编写支持响应流式传输的 Lambda 函数](https://docs.aws.amazon.com/lambda/latest/dg/config-rs-write-functions.html)。

```
export const handler = awslambda.streamifyResponse(
  async (event, responseStream, context) => {
    const httpResponseMetadata = {
      "statusCode": 200,
      "headers": {
        "x-foo": "bar"
      },
      "multiValueHeaders": {
        "x-mv1": ["hello", "world"],
        "Set-Cookie": ["c1=blue", "c2=red"]
      }
    };

    responseStream = awslambda.HttpResponseStream.from(responseStream, httpResponseMetadata);
    await new Promise(r => setTimeout(r, 1000)); // synthetic delay

    responseStream.write("First payload ");
    await new Promise(r => setTimeout(r, 1000)); // synthetic delay

    responseStream.write("Final payload");
    responseStream.end();
});
```

------
#### [ Using the pipeline method ]

Lambda 建议，编写支持响应流式传输的函数时，使用 Node.js 原生运行时提供的 `awslambda.streamifyResponse()` 修饰器和 `pipeline()` 方法。使用 pipeline 方法时，您无需创建分隔符，Lambda 会自动处理。有关更多信息，请参阅[编写支持响应流式传输的 Lambda 函数](https://docs.aws.amazon.com/lambda/latest/dg/config-rs-write-functions.html)。

以下代码示例将 JSON 元数据对象和三个有效载荷流式传输回客户端。

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

export const handler = awslambda.streamifyResponse(
  async (event, responseStream, context) => {
    const httpResponseMetadata = {
      statusCode: 200,
      headers: {
        "Content-Type": "text/plain",
        "X-Custom-Header": "Example-Custom-Header"
      }
    };

    responseStream = awslambda.HttpResponseStream.from(responseStream, httpResponseMetadata);

    const dataStream = Readable.from(async function* () {
      yield "FIRST payload\n";
      await new Promise(r => setTimeout(r, 1000));
      yield "SECOND payload\n";
      await new Promise(r => setTimeout(r, 1000));
      yield "THIRD payload\n";
      await new Promise(r => setTimeout(r, 1000));
    }());

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

------
#### [ Without using the pipeline method ]

以下代码示例在不使用 `awslambda.HttpResponseStream()` 方法的情况下，将 JSON 元数据对象和三个有效载荷流式传输回客户端。若未使用 `awslambda.HttpResponseStream()` 方法，您必须在元数据和有效载荷之间添加 8 个空字节的分隔符。

```
export const handler = awslambda.streamifyResponse(async (event, response, ctx) => {
  response.write('{"statusCode": 200, "headers": {"hdr-x": "val-x"}}');
  response.write("\x00".repeat(8)); // DELIMITER
  await new Promise(r => setTimeout(r, 1000));

  response.write("FIRST payload");
  await new Promise(r => setTimeout(r, 1000));

  response.write("SECOND payload");
  await new Promise(r => setTimeout(r, 1000));

  response.write("FINAL payload");
  response.end();
});
```

------

## 创建采用有效载荷响应流式传输的 Lambda 代理集成
<a name="response-streaming-lambda-create"></a>

以下步骤展示了如何创建采用有效载荷响应流式传输的 Lambda 代理集成。使用示例 Lambda 函数或创建自己的函数。

------
#### [ AWS 管理控制台 ]

**创建采用有效载荷响应流式传输的 Lambda 代理集成**

1. 通过以下网址登录到 Amazon API Gateway 控制台：[https://console.aws.amazon.com/apigateway](https://console.aws.amazon.com/apigateway)。

1. 选择一个 REST API。

1. 选择**创建资源**。

1. 对于**资源名称**，输入 **streaming**。

1. 选择**创建资源**。

1. 选中 **/streaming** 资源后，选择**创建方法**。

1. 对于**方法类型**，请选择 **ANY**。

1. 对于**集成类型**，选择 **Lambda**。

1. 选择 **Lambda 代理集成**。

1. 对于**响应传输模式**，请选择**流式传输**。

1. 对于 **Lambda 函数**，选择 Lambda 函数名称。

   API Gateway 控制台会自动使用 [InvokeWithResponseStream](https://docs.aws.amazon.com/lambda/latest/api/API_InvokeWithResponseStream.html) API 来调用 Lambda 函数。您负责编写支持响应流式传输的 Lambda 函数。有关示例，请参阅[用于响应流式传输的 Lambda 函数示例](#response-streaming-lambda-example)。

1. 选择**创建方法**。

创建方法后，部署您的 API。

**部署 API**

1. 选择**部署 API**。

1. 对于**阶段**，选择**新建阶段**。

1. 对于**阶段名称**，输入 **prod**。

1. （可选）对于**描述**，输入描述。

1. 选择**部署**。

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

以下步骤展示了如何导入一个 `responseTransferMode` 设置为 `STREAM` 的新 API。如果您有现有的集成 API 并想要修改 `responseTransferMode`，请参阅[更新 Lambda 代理集成的响应传输模式](#response-streaming-lambda-update)。

**创建带有效载荷响应流式传输的新 API**

1. 复制以下 Open API 文件，并将其保存为 `ResponseStreamDemoSwagger.yaml`。在此文件中，`responseTransferMode` 设置为 `STREAM`，集成 URI 设置为 `arn:aws:apigateway:us-west-1:lambda:path/2021-11-15/functions/arn:aws:lambda:us-west-1:111122223333:function:my-function-name/response-streaming-invocations`。

   将函数名 `my-function` 替换为支持响应流式传输的函数，并将凭证替换为具有允许 `apigateway` 服务调用 Lambda 函数的策略的 IAM 角色。

   ```
   openapi: "3.0.1"
   info:
     title: "ResponseStreamingDemo"
     version: "2025-04-28T17:28:25Z"
   servers:
   - url: "{basePath}"
     variables:
       basePath:
         default: "prod"
   paths:
     /lambda:
       get:
         x-amazon-apigateway-integration:
           httpMethod: "POST"
           uri: "arn:aws:apigateway:us-west-1:lambda:path/2021-11-15/functions/arn:aws:lambda:us-west-1:111122223333:function:my-function-name/response-streaming-invocations"
           type: "aws_proxy"
           timeoutInMillis: 90000
           responseTransferMode: "STREAM"
           credentials: "arn:aws:iam::111122223333:role/apigateway-lambda-role"
   ```

   您不用为凭证提供 IAM 角色，而是可以通过 Lambda 的 `add-permission` 命令添加基于资源的权限。

1. 使用以下 `import-rest-api` 命令导入您的 OpenAPI 定义：

   ```
   aws apigateway import-rest-api \
     --body 'fileb://~/ResponseStreamDemoSwagger.yaml' \
     --parameters endpointConfigurationTypes=REGIONAL \
     --region us-west-1
   ```

1. 使用以下 `create-deployment` 命令将新 API 部署到某个阶段：

   ```
   aws apigateway create-deployment \
     --rest-api-id a1b2c2 \
     --stage-name prod \
     --region us-west-1
   ```

------

### 更新 Lambda 代理集成的响应传输模式
<a name="response-streaming-lambda-update"></a>

以下步骤展示了如何更新 Lambda 代理集成的响应传输模式。当您将响应传输模式更改为流式传输时，请更新您的 Lambda 函数，使其符合响应流式传输的要求。使用示例 Lambda 函数或创建自己的函数。

------
#### [ AWS 管理控制台 ]

**更新 Lambda 代理集成的响应传输模式**

1. 通过以下网址登录到 Amazon API Gateway 控制台：[https://console.aws.amazon.com/apigateway](https://console.aws.amazon.com/apigateway)。

1. 选择一个 REST API。

1. 选择方法。

1. 在**集成请求**选项卡的**集成请求设置**下，选择**编辑**。

1. 对于**响应传输模式**，请选择**流式传输**。

1. 对于 **Lambda 函数**，选择 Lambda 函数名称。

1. 选择**保存**。

更新方法后，部署您的 API。

**部署 API**

1. 选择**部署 API**。

1. 对于**阶段**，选择**新建阶段**。

1. 对于**阶段名称**，输入 **prod**。

1. （可选）对于**描述**，输入描述。

1. 选择**部署**。

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

1. 更新您的 Lambda 函数以支持流式传输。

1. 使用以下 AWS CLI 命令更新集成 URI 和集成的响应传输模式：

   ```
   aws apigateway update-integration \
    --rest-api-id a1b2c3 \
    --resource-id aaa111 \
    --http-method ANY \
    --patch-operations "[{\"op\":\"replace\",\"path\":\"/uri\",\"value\":\"arn:aws:apigateway:us-west-1:lambda:path/2021-11-15/functions/arn:aws:lambda:us-west-1:111122223333:function:my-function-name/response-streaming-invocations\"}, {\"op\":\"replace\",\"path\":\"/responseTransferMode\",\"value\":\"STREAM\"}]" \
    --region us-west-1
   ```

1. 重新部署 API 以使更改生效。

------