

# API Gateway WebSocket API
<a name="apigateway-websocket-api"></a>

API Gateway 中的 WebSocket API 是与后端 HTTP 终端节点、Lambda 函数或其他 AWS 服务集成的 WebSocket 路由的集合。您可以使用 API Gateway 功能，帮助您处理 API 生命周期从创建到监控生产 API 的各个方面。

API Gateway WebSocket API 是双向的。客户端可以向服务发送消息，服务可以独立向客户端发送消息。这种双向行为可实现更丰富的客户端/服务交互，因为服务无需客户端发出明确请求即可将数据推送到客户端。WebSocket API 通常用于聊天应用程序、协作平台、多人游戏和金融交易平台等实时应用程序。

有关要开始使用的示例应用程序，请参阅[教程：使用 WebSocket API、Lambda 和 DynamoDB 创建 WebSocket 聊天应用程序](websocket-api-chat-app.md)。

在本节中，您可以了解如何使用 API Gateway 开发、发布、保护和监控 WebSocket API。

**Topics**
+ [API Gateway 中的 WebSocket API 概览](apigateway-websocket-api-overview.md)
+ [在 API Gateway 中开发 WebSocket API](websocket-api-develop.md)
+ [发布 WebSocket API 供客户调用](websocket-api-publish.md)
+ [保护 API Gateway 中的 WebSocket API](websocket-api-protect.md)
+ [监控 API Gateway 中的 WebSocket API](websocket-api-monitor.md)

# API Gateway 中的 WebSocket API 概览
<a name="apigateway-websocket-api-overview"></a>

在 API Gateway 中，您可以创建 WebSocket API 作为AWS服务（如 Lambda 或 DynamoDB）或 HTTP 终端节点的有状态前端。WebSocket API 根据从客户端应用程序收到的消息内容来调用您的后端。

与接收和响应请求的 REST API 不同，WebSocket API 支持客户端应用程序与后端之间的双向通信。后端可以向连接的客户端发送回调消息。

在 WebSocket API 中，传入的 JSON 消息将根据您配置的路由定向到后端集成。（非 JSON 消息将定向到您配置的 `$default` 路由。）

*路由*包含一个*路由键*，这是在评估*路由选择表达式*时预期的值。`routeSelectionExpression` 是在 API 级别定义的属性。它指定了预期存在于消息负载中的 JSON 属性。有关路由选择表达式的更多信息，请参阅[路由选择表达式](websocket-api-develop-routes.md#apigateway-websocket-api-route-selection-expressions)。

例如，如果您的 JSON 消息包含一个 `action` 属性，并且您想要根据此属性执行不同操作，则您的路由选择表达式可能是 `${request.body.action}`。您的路由表将通过将 `action` 属性的值与您在表中定义的自定义路由键值相匹配来指定要执行的操作。

## 为 WebSocket API 使用路由
<a name="apigateway-websocket-api-overview-routes"></a>

可以使用三个预定义路由：`$connect`、`$disconnect` 和 `$default`。此外，您还可以创建自定义路由。
+ API Gateway 会在客户端和 WebSocket API 之间的持久连接处于启动状态时调用 `$connect` 路由。
+ API Gateway 会在客户端或服务器与 API 断开连接时调用 `$disconnect` 路由。
+ 如果找到匹配的路由，则 API Gateway 会在针对消息评估路由选择表达式之后调用自定义路由；匹配项确定调用哪个集成。
+ 如果无法针对消息评估路径选择表达式或未找到匹配的路由，则 API Gateway 会调用 `$default` 路由。

有关 `$connect` 和 `$disconnect` 路由的更多信息，请参阅[管理连接的用户和客户端应用程序：`$connect` 和 `$disconnect` 路由](apigateway-websocket-api-route-keys-connect-disconnect.md)。

有关 `$default` 路由和自定义路由的更多信息，请参阅[在 API Gateway 中调用与 `$default` 路由和自定义路由的后端集成](apigateway-websocket-api-routes-integrations.md)。

## 向连接的客户端应用程序发送数据
<a name="apigateway-websocket-api-overview-send-data"></a>

后端服务可以将数据发送到连接的客户端应用程序。可以通过执行以下操作来发送数据：
+ 使用集成可发送响应，该响应通过您定义的路由响应返回到客户端。
+ 您可以使用 `@connections` API 发送 POST 请求。有关更多信息，请参阅 [在后端服务中使用 `@connections` 命令](apigateway-how-to-call-websocket-api-connections.md)。

## WebSocket API 状态代码
<a name="apigateway-websocket-status-codes"></a>

API Gateway WebSocket API 对于从服务器到客户端的通信使用以下状态代码，如 [WebSocket Close Code Number Registry](https://www.iana.org/assignments/websocket/websocket.xhtml#close-code-number) 中所述：

1001  
当客户端闲置 10 分钟或达到最长 2 小时的连接生命周期时，API Gateway 将返回此状态代码。

1003  
当端点收到二进制媒体类型时，API Gateway 将返回此状态代码。WebSocket API 不支持二进制媒体类型。

1005  
如果客户端发送一个没有关闭代码的关闭帧，API Gateway 将返回此状态代码。

1006  
如果连接意外关闭（例如 TCP 连接在没有 WebSocket 关闭帧的情况下关闭），API Gateway 将返回此状态代码。

1008  
当端点收到来自特定客户端的过多请求时，API Gateway 将返回此状态代码。

1009  
当端点收到的消息太大而无法处理时，API Gateway 将返回此状态代码。

1011  
当服务器出现内部错误时，API Gateway 将返回此状态代码。

1012  
如果服务重新启动，API Gateway 将返回此状态代码。

# 管理连接的用户和客户端应用程序：`$connect` 和 `$disconnect` 路由
<a name="apigateway-websocket-api-route-keys-connect-disconnect"></a>

以下部分介绍如何将 `$connect` 和 `$disconnect` 路由用于 WebSocket API。

**Topics**
+ [`$connect` 路由](#apigateway-websocket-api-routes-about-connect)
+ [从 `$connect` 路由传递连接信息](#apigateway-websocket-api-passing-connectionId-on-connect)
+ [`$disconnect` 路由](#apigateway-websocket-api-routes-about-disconnect)

## `$connect` 路由
<a name="apigateway-websocket-api-routes-about-connect"></a>

客户端应用程序通过发送 WebSocket 升级请求连接到 WebSocket API。如果请求成功，则在建立连接时会执行 `$connect` 路由。

由于 WebSocket 连接是有状态连接，因此您只能在 `$connect` 路由上配置授权。`AuthN`/`AuthZ` 仅在连接时执行。

在执行完与 `$connect` 路由关联的集成之前，升级请求处于待处理状态，将不会建立实际连接。如果 `$connect` 请求失败（例如，由于 `AuthN`/`AuthZ` 失败或集成失败），则不会建立连接。

**注意**  
如果授权在 `$connect` 上失败，则不会建立连接，客户端将收到 `401` 或 `403` 响应。

为 `$connect` 设置集成是可选的。在以下情况下，您应该考虑设置 `$connect` 集成：
+ 您希望使客户端能够使用 `Sec-WebSocket-Protocol` 字段指定子协议。有关示例代码，请参阅 [设置需要 WebSocket 子协议的 `$connect` 路由](websocket-connect-route-subprotocol.md)。
+ 您希望在客户端连接时收到通知。
+ 您希望限制连接或控制谁会连接。
+ 您希望后端使用回调 URL 将消息发送回客户端。
+ 您希望将每个连接 ID 和其他信息存储到数据库中（例如，Amazon DynamoDB）。

## 从 `$connect` 路由传递连接信息
<a name="apigateway-websocket-api-passing-connectionId-on-connect"></a>

 您可以使用代理和非代理集成将信息从 `$connect` 路由传递到数据库或其他 AWS 服务。

### 使用代理集成传递连接信息
<a name="websocket-connect-proxy-integration"></a>

您可以通过事件中的 Lambda 代理集成访问连接信息。使用其他 AWS 服务 或 AWS Lambda 函数发布到连接。

以下 Lambda 函数显示如何使用 `requestContext` 对象记录连接 ID、域名、阶段名和查询字符串。

------
#### [ Node.js ]

```
 export const handler = async(event, context) => {
    const connectId = event["requestContext"]["connectionId"]
    const domainName = event["requestContext"]["domainName"]
    const stageName = event["requestContext"]["stage"]
    const qs = event['queryStringParameters']
    console.log('Connection ID: ', connectId, 'Domain Name: ', domainName, 'Stage Name: ', stageName, 'Query Strings: ', qs )
    return {"statusCode" : 200}
};
```

------
#### [ Python ]

```
import json
import logging
logger = logging.getLogger()
logger.setLevel("INFO")


def lambda_handler(event, context):
    connectId = event["requestContext"]["connectionId"]
    domainName = event["requestContext"]["domainName"]
    stageName = event["requestContext"]["stage"]
    qs = event['queryStringParameters']
    connectionInfo = {
        'Connection ID': connectId,
        'Domain Name': domainName,
        'Stage Name': stageName,
        'Query Strings': qs}
    logging.info(connectionInfo)
    return {"statusCode": 200}
```

------

### 使用非代理集成传递连接信息
<a name="websocket-connect-non-proxy-integration"></a>
+ 您可以使用非代理集成访问连接信息。设置集成请求并提供 WebSocket API 请求模板。以下 [Velocity 模板语言（VTL）](https://velocity.apache.org/engine/devel/vtl-reference.html)映射模板提供了集成请求。此请求将以下详细信息发送给非代理集成：
  + 连接 ID
  + 域名
  + 阶段名称
  + 路径
  + 标头
  + 查询字符串

  此请求将连接 ID、域名、阶段名、路径、标头和查询字符串发送到非代理集成。

  ```
  {
      "connectionId": "$context.connectionId",
      "domain": "$context.domainName",
      "stage": "$context.stage",
      "params": "$input.params()"
  }
  ```

  有关设置数据转换的更多信息，请参阅[针对 API Gateway 中的 WebSocket API 的数据转换](websocket-api-data-transformations.md)。

  要完成集成请求，请为集成响应设置 `StatusCode: 200`。要了解有关设置集成响应的更多信息，请参阅[使用 API Gateway 控制台设置集成响应](apigateway-websocket-api-integration-responses.md#apigateway-websocket-api-integration-response-using-console)。

## `$disconnect` 路由
<a name="apigateway-websocket-api-routes-about-disconnect"></a>

在连接关闭后，会执行 `$disconnect` 路由。

连接可以由服务器或客户端关闭。由于连接在执行时已经关闭，因此 `$disconnect` 是最适合的事件。API Gateway 将尽最大努力将 `$disconnect` 事件传送到您的集成，但它不能保证交付。

后端可以使用 `@connections` API 启动断开连接。有关更多信息，请参阅 [在后端服务中使用 `@connections` 命令](apigateway-how-to-call-websocket-api-connections.md)。

# 在 API Gateway 中调用与 `$default` 路由和自定义路由的后端集成
<a name="apigateway-websocket-api-routes-integrations"></a>

以下部分介绍如何使用 WebSocket API 的 `$default` 路由或自定义路由来调用后端集成。

**Topics**
+ [使用路由处理消息](#apigateway-websocket-api-overview-routes)
+ [`$default` 路由](#apigateway-websocket-api-routes-about-default)
+ [自定义路由](#apigateway-websocket-api-routes-about-custom)
+ [使用 API Gateway WebSocket API 集成连接到您的业务逻辑](#apigateway-websocket-api-overview-integrations)
+ [WebSocket API 和 REST API 之间的重要区别](#apigateway-websocket-api-overview-integrations-differences)

## 使用路由处理消息
<a name="apigateway-websocket-api-overview-routes"></a>

在 API Gateway WebSocket API 中，消息可以从客户端发送到后端服务，反之亦然。与 HTTP 的请求/响应模型不同，在 WebSocket 中，后端可以在客户端不采取任何操作的情况下向客户端发送消息。

消息可以是 JSON 或非 JSON。但是，只有 JSON 消息可以根据消息内容路由到特定的集成。非 JSON 消息通过 `$default` 路由传递到后端。

**注意**  
API Gateway 支持最大 128 KB 的消息负载，最大帧大小为 32 KB。如果消息超过 32 KB，则必须将其拆分为多个帧，每个 32 KB 或更小。如果接收到更大的消息（或帧），则连接会关闭并显示代码 1009。  
目前不支持二进制负载。如果接收到二进制帧，则连接会关闭并显示代码 1003。但是，可以将二进制负载转换为文本。请参阅 [针对 API Gateway 中的 WebSocket API 的二进制媒体类型](websocket-api-develop-binary-media-types.md)。

使用 API Gateway 中的 WebSocket API，可以路由 JSON 消息以根据消息内容执行特定的后端服务。当客户端通过其 WebSocket 连接发送消息时，这会导致对 WebSocket API 的*路由请求*。请求将与 API Gateway 中具有相应路由键的路由匹配。您可以在 API Gateway 控制台中使用 AWS CLI 或AWS开发工具包为 WebSocket API 设置路由请求。

**注意**  
在 AWS CLI 和 AWS 开发工具包中，您可以在创建集成之前或之后创建路由。目前，控制台不支持重用集成，因此您必须先创建路由，然后为该路由创建集成。

您可以配置 API Gateway，使其在继续集成请求之前对路由请求执行验证。如果验证失败，API Gateway 会在不调用后端的情况下使请求失败，向客户端发送类似于以下内容的 `"Bad request body"` 网关响应，并在 CloudWatch Logs 中发布验证结果：

```
{"message" : "Bad request body", "connectionId": "{connectionId}", "messageId": "{messageId}"}
```

这样可以减少对后端的不必要调用，并让您专注于 API 的其他要求。

您还可以为 API 的路由定义路由响应，以启用双向通信。路由响应描述了在完成特定路由的集成后将向客户端发送的数据。例如，如果您希望客户端向后端发送消息而不收到响应（单向通信），则无需为路由定义响应。但是，如果您不提供路由响应，API Gateway 将不会向您的客户端发送有关您的集成结果的任何信息。

## `$default` 路由
<a name="apigateway-websocket-api-routes-about-default"></a>

每个 API Gateway WebSocket API 都可以有一个 `$default` 路由。这是一个特殊的路由值，可以通过以下方式使用：
+ 您可以将它与已定义的路由键一起使用，来为与任何已定义路由键不匹配的传入消息指定“回退”路由（例如，返回特定错误消息的通用模拟集成）。
+ 您可以在没有任何已定义路由键的情况下使用它，来指定将路由委派给后端组件的代理模型。
+ 您可以使用它为非 JSON 负载指定路由。

## 自定义路由
<a name="apigateway-websocket-api-routes-about-custom"></a>

如果您希望根据消息内容来调用特定集成，则可以通过创建自定义路由来实现。

自定义路由使用您指定的路由键和集成。当传入消息包含 JSON 属性，并且该属性的计算结果为与路由键值匹配的值时，API Gateway 将会调用集成。（有关更多信息，请参阅 [API Gateway 中的 WebSocket API 概览](apigateway-websocket-api-overview.md)。）

例如，假设您要创建聊天室应用程序。您可以从创建 WebSocket API 开始，其路径选择表达式为 `$request.body.action`。然后，您可以定义两个路由：`joinroom` 和 `sendmessage`。客户端应用程序可以通过发送如下消息来调用 `joinroom` 路由：

```
{"action":"joinroom","roomname":"developers"}
```

而且，它可以通过发送如下消息来调用 `sendmessage` 路由：

```
{"action":"sendmessage","message":"Hello everyone"}
```

## 使用 API Gateway WebSocket API 集成连接到您的业务逻辑
<a name="apigateway-websocket-api-overview-integrations"></a>

为 API Gateway WebSocket API 设置路由后，您必须指定您想使用的集成。与路由可以具有路由请求和路由响应一样，集成可以具有*集成请求*和*集成响应*。*集成请求*包含后端预期的信息，用以处理来自客户端的请求。*集成响应* 包含后端返回到 API Gateway 的数据，可用于构造要发送给客户端的消息（如果定义了路由响应）。

有关设置集成的更多信息，请参阅[API Gateway 中 WebSocket API 的集成](apigateway-websocket-api-integrations.md)。

## WebSocket API 和 REST API 之间的重要区别
<a name="apigateway-websocket-api-overview-integrations-differences"></a>

WebSocket API 的集成类似于 REST API 的集成，但有以下区别：
+ 目前，在 API Gateway 控制台中，您必须先创建一个路径，然后创建一个集成作为该路由的目标。但是，在 API 和 CLI 中，您可以按任何顺序独立创建路由和集成。
+ 您可以对多个路由使用单个集成。例如，如果您有一组彼此密切相关的操作，您可能希望所有这些路由都转到单个 Lambda 函数。您可以一次指定集成的详细信息并将其分配给每个相关路由，而不是多次定义它。
**注意**  
目前，控制台不支持重用集成，因此您必须先创建路由，然后为该路由创建集成。  
在 AWS CLI 和 AWS 开发工具包中，您可以通过将路由的目标设置 `"integrations/{integration-id}"` 的值来重用集成，其中 `{integration-id}"` 是要与路由关联的集成的唯一 ID。
+ API Gateway 提供多个[选择表达式](apigateway-websocket-api-selection-expressions.md)，您可以在路由和集成中使用它们。您无需依赖内容类型来选择输入模板或输出映射。与路径选择表达式一样，您可以定义要由 API Gateway 评估的选择表达式以选择正确的项。如果找不到匹配的模板，则所有这些都将回退到 `$default` 模板。
  + 在集成请求中，模板选择表达式支持 `$request.body.<json_path_expression>` 和静态值。
  + 在集成响应中，模板选择表达式支持 `$request.body.<json_path_expression>`、`$integration.response.statuscode`、`$integration.response.header.<headerName>` 和静态值。

在 HTTP 协议中，请求和响应是同步发送的，通信基本上是单向的。在 WebSocket 协议中，通信是双向的。响应是异步的，客户端不一定以与发送客户端消息相同的顺序接收响应。此外，后端可以向客户端发送消息。

**注意**  
对于配置为使用 `AWS_PROXY` 或 `LAMBDA_PROXY` 集成的路由，通信是单向的，而 API Gateway 不会自动将后端响应传递给路由响应。例如，对于 `LAMBDA_PROXY` 集成，Lambda 函数返回的正文将不会返回到客户端。如果希望客户端接收集成响应，则必须定义路由响应以使双向通信成为可能。

# WebSocket 选择表达式
<a name="apigateway-websocket-api-selection-expressions"></a>

API Gateway 使用选择表达式作为一种评估请求和响应上下文并生成键的方法。然后，该键用于从通常由您，即 API 开发人员提供的一组可能值中进行选择。确切的受支持变量集将因特定表达式而异。下文更为详细地描述了每个表达式。

对于所有表达式，该语言遵循相同的规则集：
+ 变量以 `"$"` 为前缀。
+ 大括号可用于明确定义变量边界，例如，`"${request.body.version}-beta"`。
+ 支持多个变量，但评估仅发生一次（无递归评估）。
+ 可以使用 `$` 对美元符号 (`"\"`) 进行转义。这在定义映射到保留的 `$default` 键（例如 `"\$default"`）的表达式时非常有用。
+ 在某些情况下，需要模式格式。在这种情况下，表达式应该用正斜杠 (`"/"`) 包装起来，例如，`"/2\d\d/"`，以便匹配 `2XX` 状态代码。

**Topics**
+ [路由响应选择表达式](#apigateway-websocket-api-route-response-selection-expressions)
+ [API 键选择表达式](#apigateway-websocket-api-apikey-selection-expressions)
+ [API 映射选择表达式](#apigateway-websocket-api-mapping-selection-expressions)
+ [WebSocket 选择表达式摘要](#apigateway-websocket-api-selection-expression-table)

## 路由响应选择表达式
<a name="apigateway-websocket-api-route-response-selection-expressions"></a>

[路由响应](apigateway-websocket-api-route-response.md)用于对从后端到客户端的响应建模。对于 WebSocket API，路由响应是可选的。定义后，它向 API Gateway 发出信号，表示它应该在收到 WebSocket 消息时向客户端返回响应。

*路由响应选择表达式*的求解会产生路由响应键。最终，此密钥将用于从与 API 相关联的一个 [https://docs.aws.amazon.com/apigatewayv2/latest/api-reference/apis-apiid-routes-routeid-routeresponses.html](https://docs.aws.amazon.com/apigatewayv2/latest/api-reference/apis-apiid-routes-routeid-routeresponses.html) 中进行选择。但是，目前仅支持 `$default` 键。

## API 键选择表达式
<a name="apigateway-websocket-api-apikey-selection-expressions"></a>

如果服务确定仅当客户端提供有效的 [API 键](api-gateway-basic-concept.md#apigateway-definition-api-key)时给定的请求才应继续，则会求解此表达式。

目前，仅支持的两个值是 `$request.header.x-api-key` 和 `$context.authorizer.usageIdentifierKey`。

## API 映射选择表达式
<a name="apigateway-websocket-api-mapping-selection-expressions"></a>

将会求解估此表达式以确定在使用自定义域发出请求时选择哪个 API 阶段。

目前，唯一支持的值是 `$request.basepath`。

## WebSocket 选择表达式摘要
<a name="apigateway-websocket-api-selection-expression-table"></a>

下表总结了 WebSocket API 中的选择表达式的用例：


| 选择表达式 | 求解为以下对象的键 | 备注 | 示例使用案例 | 
| --- | --- | --- | --- | 
| Api.RouteSelectionExpression | Route.RouteKey | \$1default支持 作为包罗万象的路由。 | 根据客户端请求的上下文路由 WebSocket 消息。 | 
| Route.ModelSelectionExpression | Route.RequestModels 的键 | 可选。 如果是为非代理集成提供的，则会发生模型验证。 `$default`支持 作为包罗万象的路由。  | 在同一路径中动态执行请求验证。 | 
| Integration.TemplateSelectionExpression | Integration.RequestTemplates 的键 |  可选。 可以为非代理集成提供，用于处理传入的负载。 `${request.body.jsonPath}`支持 和静态值。 `$default`支持 作为包罗万象的路由。  | 根据请求的动态属性处理调用方的请求。 | 
| Integration.IntegrationResponseSelectionExpression | IntegrationResponse.IntegrationResponseKey |  可选。可以为非代理集成提供。 充当错误消息（来自 Lambda）或状态代码（来自 HTTP 集成）的模式匹配。 `$default`非代理集成需要 来充当包罗万象的成功响应。  |  处理来自后端的响应。 选择根据后端的动态响应发生的操作（例如，明显地处理某些错误）。  | 
| IntegrationResponse.TemplateSelectionExpression | IntegrationResponse.ResponseTemplates 的键 | 可选。可以为非代理集成提供。支持 \$1default。  |  在某些情况下，响应的动态属性可能决定相同路径和相关集成内的不同变换。 支持 `${request.body.jsonPath}`、`${integration.response.statuscode}`、`${integration.response.header.headerName}`、`${integration.response.multivalueheader.headerName}` 和静态值。 `$default`支持 作为包罗万象的路由。  | 
| Route.RouteResponseSelectionExpression | RouteResponse.RouteResponseKey |  应提供以对 WebSocket 路由启动双向通信。 目前，此值仅限于 `$default`。  |  | 
| RouteResponse.ModelSelectionExpression | RouteResponse.RequestModels 的键 | 目前不受支持。 |  | 

# 在 API Gateway 中开发 WebSocket API
<a name="websocket-api-develop"></a>

本节提供有关开发 API Gateway API 时所需的 API Gateway 功能的详细信息。

在开发 API Gateway API 时，您可以决定 API 的许多特征。这些特征取决于 API 的使用案例。例如，您可能希望仅允许某些客户端调用您的 API，或者您可能希望它对所有人都可用。您可能需要 API 调用来执行 Lambda 函数、进行数据库查询或调用应用程序。

**Topics**
+ [在 API Gateway 中创建 WebSocket API](apigateway-websocket-api-create-empty-api.md)
+ [API Gateway 中 WebSocket API 的 IP 地址类型](websocket-api-ip-address-type.md)
+ [为 API Gateway 中的 WebSocket API 创建路由](websocket-api-develop-routes.md)
+ [在 API Gateway 中控制和管理对 WebSocket API 的访问](apigateway-websocket-api-control-access.md)
+ [API Gateway 中 WebSocket API 的集成](apigateway-websocket-api-integrations.md)
+ [针对 API Gateway 中的 WebSocket API 的请求验证](websocket-api-request-validation.md)
+ [针对 API Gateway 中的 WebSocket API 的数据转换](websocket-api-data-transformations.md)
+ [针对 API Gateway 中的 WebSocket API 的二进制媒体类型](websocket-api-develop-binary-media-types.md)
+ [调用 WebSocket API](apigateway-how-to-call-websocket-api.md)

# 在 API Gateway 中创建 WebSocket API
<a name="apigateway-websocket-api-create-empty-api"></a>

您可以使用 AWS CLI [create-api](https://docs.aws.amazon.com/cli/latest/reference/apigatewayv2/create-api.html) 命令或使用 AWS SDK 中的 `CreateApi` 命令，在 API Gateway 控制台中创建 WebSocket API。以下过程说明如何创建新的 WebSocket API。

**注意**  
WebSocket API 仅支持 TLS 1.2 和 TLS 1.3。不支持早期 TLS 版本。

## 使用 AWS CLI 命令创建 WebSocket API
<a name="apigateway-websocket-api-create-using-awscli"></a>

以下 [create-api](https://docs.aws.amazon.com/cli/latest/reference/apigatewayv2/create-api.html) 命令创建具有 `$request.body.action` 路由选择表达式的 API：

```
aws apigatewayv2 --region us-east-1 create-api --name "myWebSocketApi3" --protocol-type WEBSOCKET --route-selection-expression '$request.body.action'
```

输出内容如下所示：

```
{
    "ApiKeySelectionExpression": "$request.header.x-api-key",
    "Name": "myWebSocketApi3",
    "CreatedDate": "2018-11-15T06:23:51Z",
    "ProtocolType": "WEBSOCKET",
    "RouteSelectionExpression": "'$request.body.action'",
    "ApiId": "aabbccddee"
}
```

## 使用 API Gateway 控制台创建 WebSocket API
<a name="apigateway-websocket-api-create-using-console"></a>

您可以通过选择 WebSocket 协议并为 API 命名来在控制台中创建 WebSocket API。

**重要**  
创建 API 后，您无法更改为其选择的协议。无法将 WebSocket API 转换为 REST API，反之亦然。

**使用 API Gateway 控制台创建 WebSocket API**

1. 登录 API Gateway 控制台，然后选择**创建 API**。

1. 在 ** WebSocket API** 下，选择**构建**。仅支持区域端点。

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

1. 对于**路由选择表达式**，输入一个值。例如，`$request.body.action`。

   有关路由选择表达式的更多信息，请参阅[路由选择表达式](websocket-api-develop-routes.md#apigateway-websocket-api-route-selection-expressions)。

1. 请执行以下操作之一：
   + 选择**创建空白 API**，以创建没有路由的 API。
   + 选择**下一步**，将路由附加到 API。

   您可以在创建 API 之后附加路由。

# API Gateway 中 WebSocket API 的 IP 地址类型
<a name="websocket-api-ip-address-type"></a>

创建 API 时，您指定可以调用您的 API 的 IP 地址的类型。可以选择 IPv4 来解析 IPv4 地址以调用 API，也可以选择双堆栈以同时支持 IPv4 和 IPv6 地址调用 API。我们建议您将 IP 地址类型设置为双堆栈，以缓解 IP 空间耗尽或保护您的安全状况。有关双堆栈 IP 地址类型的优势的更多信息，请参阅 [IPv6 on AWS](https://docs.aws.amazon.com/whitepapers/latest/ipv6-on-aws/internet-protocol-version-6.html)。

## IP 地址类型的注意事项
<a name="websocket-api-ip-address-type-considerations"></a>

以下注意事项可能会影响您对 IP 地址类型的使用：
+ 所有 WebSocket API 的默认 IP 地址类型均为 IPv4。
+ 如果您将现有 API 的 IP 地址类型从 IPv4 更改为双堆栈，请确认任何控制 API 访问权限的策略均已更新以考虑 IPv6 调用。更改 IP 地址类型后，更改将立即生效。
+ 您的 API 可以映射到与 API 具有不同 IP 地址类型的自定义域名。如果您禁用默认 API 端点，则这可能会影响调用方调用 API 的方式。

## 更改 WebSocket API 的 IP 地址类型
<a name="websocket-api-ip-address-type-change"></a>

您可以通过更新 API 的配置来更改 IP 地址类型。您可以使用 AWS 管理控制台、AWS CLI、CloudFormation 或 AWS SDK 更新 API 的配置。如果您更改 API 的 IP 地址类型，您不需要重新部署 API 即可使更改生效。

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

**更改 WebSocket API 的 IP 地址类型**

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

1. 选择 WebSocket API。

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

1. 对于 IP 地址类型，选择 **IPv4** 或**双堆栈**。

1. 选择**保存**。

   对 API 配置的更改将立即生效。

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

以下 [update-api](https://docs.aws.amazon.com/cli/latest/reference/apigatewayv2/update-api.html) 命令将 API 更新为具有双堆栈 IP 地址类型：

```
aws apigatewayv2 update-api \
    --api-id abcd1234 \
    --ip-address-type dualstack
```

输出将与以下内容类似：

```
{
    "ApiEndpoint": "https://abcd1234.execute-api.us-east-1.amazonaws.com",
    "ApiId": "abcd1234",
    "ApiKeySelectionExpression": "$request.header.x-api-key",
    "CreatedDate": "2025-02-04T22:20:20+00:00",
    "DisableExecuteApiEndpoint": false,
    "Name": "My-WebSocket-API",
    "ProtocolType": "WEBSOCKET",
    "RouteSelectionExpression": "$request.method $request.path",
    "Tags": {},
    "NotificationUris": [],
    "IpAddressType": "dualstack"
}
```

------

# 为 API Gateway 中的 WebSocket API 创建路由
<a name="websocket-api-develop-routes"></a>

在 WebSocket API 中，传入的 JSON 消息将根据您配置的路由定向到后端集成。（非 JSON 消息将定向到您配置的 `$default` 路由。）

*路由*包含一个*路由键*，这是在评估*路由选择表达式*时预期的值。`routeSelectionExpression` 是在 API 级别定义的属性。它指定了预期存在于消息负载中的 JSON 属性。有关路由选择表达式的更多信息，请参阅[路由选择表达式](#apigateway-websocket-api-route-selection-expressions)。

例如，如果您的 JSON 消息包含一个 `action` 属性，并且您想要根据此属性执行不同操作，则您的路由选择表达式可能是 `${request.body.action}`。您的路由表将通过将 `action` 属性的值与您在表中定义的自定义路由键值相匹配来指定要执行的操作。

可以使用三个预定义路由：`$connect`、`$disconnect` 和 `$default`。此外，您还可以创建自定义路由。
+ API Gateway 会在客户端和 WebSocket API 之间的持久连接处于启动状态时调用 `$connect` 路由。
+ API Gateway 会在客户端或服务器与 API 断开连接时调用 `$disconnect` 路由。
+ 如果找到匹配的路由，则 API Gateway 会在针对消息评估路由选择表达式之后调用自定义路由；匹配项确定调用哪个集成。
+ 如果无法针对消息评估路径选择表达式或未找到匹配的路由，则 API Gateway 会调用 `$default` 路由。

## 路由选择表达式
<a name="apigateway-websocket-api-route-selection-expressions"></a>

当服务正在为传入消息选择要遵循的路由时，将会对*路由选择表达式*进行求解。该服务使用其 `routeKey` 与求解值完全匹配的路由。如果没有匹配项，并且存在具有 `$default` 路由键的路由，则将选择该路由。如果没有路由与求解值匹配，并且没有 `$default` 路由，则该服务将返回错误。对于基于 WebSocket 的 API，表达式的格式应为 `$request.body.{path_to_body_element}`。

例如，假设您要发送以下 JSON 消息：

```
{
    "service" : "chat",
    "action" : "join",
    "data" : {
        "room" : "room1234"
   }
}
```

您可能希望根据 `action` 属性选择 API 的行为。在这种情况下，您可以定义以下路由选择表达式：

```
$request.body.action
```

在此示例中，`request.body` 是指您的消息的 JSON 负载，`.action` 是 [JSONPath](https://goessner.net/articles/JsonPath/) 表达式。您可以在 `request.body` 之后使用任何 JSON 路径表达式，但请记住，结果将会字符串化。例如，如果您的 JSONPath 表达式返回包含两个元素的数组，那么它将显示为字符串 `"[item1, item2]"`。因此，最好将表达式求解为值而不是数组或对象。

您可以仅使用一个静态值，也可以使用多个变量。下表显示了针对上述负载的示例及其求解结果。


| 表达式 | 求解结果 | 说明 | 
| --- | --- | --- | 
| \$1request.body.action | join | 未包装的变量 | 
| \$1\$1request.body.action\$1 | join | 包装的变量 | 
| \$1\$1request.body.service\$1/\$1\$1request.body.action\$1 | chat/join | 具有静态值的多个变量 | 
| \$1\$1request.body.action\$1-\$1\$1request.body.invalidPath\$1  | join- | 如果找不到 JSONPath，则变量将解析为 ""。 | 
| action | action | 静态值 | 
| \$1\$1default | \$1default | 静态值 | 

求解结果将用于查找路由。如果存在具有匹配路由键的路由，则将选择该路由来处理消息。如果找不到匹配的路由，则 API Gateway 尝试查找 `$default` 路由（如果可用）。如果未定义 `$default` 路由，则 API Gateway 将返回错误。

## 在 API Gateway 中为 WebSocket API 设置路由
<a name="apigateway-websocket-api-routes"></a>

首次创建新的 WebSocket API 时，有三个预定义的路由：`$connect`、`$disconnect` 和 `$default`。您可以使用控制台、API 或 AWS CLI 创建它们。如果需要，您可以创建自定义路由。有关更多信息，请参阅 [API Gateway 中的 WebSocket API 概览](apigateway-websocket-api-overview.md)。

**注意**  
在 CLI 中，您可以在创建集成之前或之后创建路由，并且可以为多个路由重用相同的集成。

### 使用 API Gateway 控制台创建路由
<a name="apigateway-websocket-api-route-using-console"></a>

**使用 API Gateway 控制台创建路由**

1. 登录到 API Gateway 控制台，选择 API，然后选择**路由**。

1. 选择**创建路由**。

1. 在**路径密钥**中，输入路径密钥名称。您可以创建预定义路由（`$connect`、`$disconnect` 和 `$default`），也可以创建自定义路由。
**注意**  
当您创建自定义路由时，请勿在路由键名称中使用 `$` 前缀。此前缀是专为预定义路由预留的。

1. 选择并配置路径的集成类型。有关更多信息，请参阅 [使用 API Gateway 控制台设置 WebSocket API 集成请求](apigateway-websocket-api-integration-requests.md#apigateway-websocket-api-integration-request-using-console)。

### 使用 AWS CLI 创建路由
<a name="apigateway-websocket-api-route-using-awscli"></a>

以下 [create-route](https://docs.aws.amazon.com/cli/latest/reference/apigatewayv2/create-route.html) 命令创建路由：

```
aws apigatewayv2 --region us-east-1 create-route --api-id aabbccddee --route-key $default
```

输出与以下内容类似：

```
{
    "ApiKeyRequired": false,
    "AuthorizationType": "NONE",
    "RouteKey": "$default",
    "RouteId": "1122334"
}
```

### 为 `$connect` 指定路由请求设置
<a name="apigateway-websocket-api-route-request-connect"></a>

当您为 API 设置 `$connect` 路由时，可以使用以下可选设置为 API 启用授权。有关更多信息，请参阅 [`$connect` 路由](apigateway-websocket-api-route-keys-connect-disconnect.md#apigateway-websocket-api-routes-about-connect)。
+ **Authorization (授权)**：如果不需要授权，您可以指定 `NONE`。否则，您可以指定：
  + `AWS_IAM`，以使用标准AWS IAM 策略来控制对 API 的访问。
  + `CUSTOM`，以通过指定先前创建的 Lambda 授权方函数来实现 API 的授权。授权方可以驻留在您自己的AWS账户或其他AWS账户中。有关 Lambda 授权方的更多信息，请参阅 [使用 API Gateway Lambda 授权方](apigateway-use-lambda-authorizer.md)。
**注意**  
在 API Gateway 控制台中，只有在您设置了如`CUSTOM`中所述的授权方函数后，[配置 Lambda 授权方（控制台）](configure-api-gateway-lambda-authorization.md#configure-api-gateway-lambda-authorization-with-console) 设置才可见。
**重要**  
**Authorization (授权)** 设置将会应用于整个 API，而不仅仅是 `$connect` 路由。`$connect` 路由保护其他路由，因为它在每个连接上都会被调用。
+ **需要 API 密钥**：您可以选择要求为 API 的 `$connect` 路由提供 API 密钥。您可以将 API 键与使用计划一起使用来控制和跟踪对 API 的访问。有关更多信息，请参阅 [API Gateway 中针对 REST API 的使用计划和 API 密钥](api-gateway-api-usage-plans.md)。

### 使用 API Gateway 控制台设置 `$connect` 路由请求
<a name="apigateway-websocket-api-connect-route-request-using-console"></a>

要使用 API Gateway 控制台为 WebSocket API 设置 `$connect` 路由请求，请执行以下操作：

1. 登录到 API Gateway 控制台，选择 API，然后选择**路由**。

1. 在**路由**下选择 `$connect`，或按照[使用 API Gateway 控制台创建路由](#apigateway-websocket-api-route-using-console)创建 `$connect` 路由。

1. 在**路由请求设置**部分中，选择**编辑**。

1. 对于**授权**，选择一种授权类型。

1. 要为 `$connect` 路由要求 API，请选择**需要 API 密钥**。

1. 选择**保存更改**。

# 为 API Gateway 中的 WebSocket API 设置路由响应
<a name="apigateway-websocket-api-route-response"></a>

WebSocket 路由可以配置为双向或单向通信。除非您设置了路由响应，否则 API Gateway 不会将后端响应传递给路由响应。

**注意**  
您只能为 WebSocket API 定义 `$default` 路由响应。您可以使用集成响应来处理来自后端服务的响应。有关更多信息，请参阅 [集成响应概述](apigateway-websocket-api-integration-responses.md#apigateway-websocket-api-integration-response-overview)。

您可以使用 API Gateway 控制台、AWS CLI 或AWS开发工具包配置路由响应和响应选择表达式。

有关路由响应选择表达式的更多信息，请参阅[路由响应选择表达式](apigateway-websocket-api-selection-expressions.md#apigateway-websocket-api-route-response-selection-expressions)。

**Topics**
+ [使用 API Gateway 控制台设置路由响应](#apigateway-websocket-api-route-response-using-console)
+ [使用 AWS CLI 设置路由响应](#apigateway-websocket-api-route-response-using-awscli)

## 使用 API Gateway 控制台设置路由响应
<a name="apigateway-websocket-api-route-response-using-console"></a>

在创建 WebSocket API 并将代理 Lambda 函数附加到默认路由后，您可以使用 API Gateway 控制台设置路由响应：

1. 登录 API Gateway 控制台，对于 `$default` 路由选择集成了代理 Lambda 函数的 WebSocket API。

1. 在 **Routes**（路由）下，选择 `$default` 路由。

1. 选择**启用双向通信**。

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

1. 将 API 部署到阶段。

 使用以下 [wscat](https://www.npmjs.com/package/wscat) 命令连接到您的 API。有关 `wscat` 的更多信息，请参阅[使用 `wscat` 连接到 WebSocket API 并向其发送消息](apigateway-how-to-call-websocket-api-wscat.md)。

```
wscat -c wss://api-id.execute-api.us-east-2.amazonaws.com/test
```

 按 Enter 键以调用默认路由。应返回您的 Lambda 函数的主体。

## 使用 AWS CLI 设置路由响应
<a name="apigateway-websocket-api-route-response-using-awscli"></a>

以下 [create-route-response](https://docs.aws.amazon.com/cli/latest/reference/apigatewayv2/create-route-response.html) 命令为 `$default` 路由创建路由响应。您可以使用 [get-apis](https://docs.aws.amazon.com/cli/latest/reference/apigatewayv2/get-apis.html) 和 [get-routes](https://docs.aws.amazon.com/cli/latest/reference/apigatewayv2/get-routes.html) 命令来确定 API ID 和路由 ID。

```
aws apigatewayv2 create-route-response \
    --api-id aabbccddee \
    --route-id 1122334  \
    --route-response-key '$default'
```

输出将与以下内容类似：

```
{
    "RouteResponseId": "abcdef",
    "RouteResponseKey": "$default"
}
```

# 设置需要 WebSocket 子协议的 `$connect` 路由
<a name="websocket-connect-route-subprotocol"></a>

在连接到 WebSocket API 期间，客户端可以使用 `Sec-WebSocket-Protocol` 字段请求 [WebSocket 子协议](https://datatracker.ietf.org/doc/html/rfc6455#page-12)。您可以为 `$connect` 路由设置集成，以便仅当客户端请求您的 API 支持的子协议时允许连接。

以下示例 Lambda 函数将 `Sec-WebSocket-Protocol` 标头返回给客户端。仅当客户端指定 `myprotocol` 子协议时，此函数才会建立与 API 的连接。

如需创建此示例 API 和 Lambda 代理集成的 CloudFormation 模板，请参阅 [samples/ws-subprotocol.zip](samples/ws-subprotocol.zip)。

```
export const handler = async (event) => {
    if (event.headers != undefined) {
        const headers = toLowerCaseProperties(event.headers);
        
        if (headers['sec-websocket-protocol'] != undefined) {
            const subprotocolHeader = headers['sec-websocket-protocol'];
            const subprotocols = subprotocolHeader.split(',');
            
            if (subprotocols.indexOf('myprotocol') >= 0) {
                const response = {
                    statusCode: 200,
                    headers: {
                        "Sec-WebSocket-Protocol" : "myprotocol"
                    }
                };
                return response;
            }
        }
    }
    
    const response = {
        statusCode: 400
    };
        
    return response;
};

function toLowerCaseProperties(obj) {
    var wrapper = {};
    for (var key in obj) {
        wrapper[key.toLowerCase()] = obj[key];
    }
    return wrapper;
}
```

您可以使用 [https://www.npmjs.com/package/wscat](https://www.npmjs.com/package/wscat) 测试您的 API，以确定是否仅当客户端请求 API 支持的子协议时允许连接。以下命令在连接过程中使用 `-s` 标志指定子协议。

以下命令尝试使用不受支持的子协议进行连接。由于客户端指定了 `chat1` 子协议，因此，Lambda 集成将返回 400 错误，并且连接将失败。

```
wscat -c wss://api-id.execute-api.region.amazonaws.com/beta -s chat1
error: Unexpected server response: 400
```

以下命令在连接请求中包含支持的子协议。Lambda 集成允许连接。

```
wscat -c wss://api-id.execute-api.region.amazonaws.com/beta -s chat1,myprotocol
connected (press CTRL+C to quit)
```

要了解有关调用 WebSocket API 的更多信息，请参阅[调用 WebSocket API](apigateway-how-to-call-websocket-api.md)。

# 在 API Gateway 中控制和管理对 WebSocket API 的访问
<a name="apigateway-websocket-api-control-access"></a>

API Gateway 支持多种用于控制和管理对 WebSocket API 的访问的机制：

您可以使用以下机制进行身份验证和授权：
+ ‭**标准‭AWS‬ IAM 角色和策略**提供灵活且稳健的访问控制。提供灵活且稳健的访问控制。您可以使用 IAM 角色和策略来控制哪些人可以创建和管理您的 API，以及谁可以调用它们。有关更多信息，请参阅 [利用 IAM 授权来控制对 WebSocket API 的访问](apigateway-websocket-control-access-iam.md)。
+ **IAM 标签** 可与 IAM 策略结合使用来控制访问权限。有关更多信息，请参阅 [使用标签控制对 API Gateway REST API 资源的访问](apigateway-tagging-iam-policy.md)。
+ **Lambda 授权方** 是控制对 API 的访问的 Lambda 函数。有关更多信息，请参阅 [利用 AWS Lambda REQUEST 授权方来控制对 WebSocket API 的访问](apigateway-websocket-api-lambda-auth.md)。

为了改善您的安全状况，我们建议您在所有 WebSocket API 上为 `$connect` 路由配置授权方。为遵守各种合规性框架，您可能需要执行此操作。有关更多信息，请参阅《AWS Security Hub User Guide》**中的 [Amazon API Gateway Controls](https://docs.aws.amazon.com/securityhub/latest/userguide/apigateway-controls.html)。

**Topics**
+ [利用 IAM 授权来控制对 WebSocket API 的访问](apigateway-websocket-control-access-iam.md)
+ [利用 AWS Lambda REQUEST 授权方来控制对 WebSocket API 的访问](apigateway-websocket-api-lambda-auth.md)

# 利用 IAM 授权来控制对 WebSocket API 的访问
<a name="apigateway-websocket-control-access-iam"></a>

WebSocket API 中的 IAM 授权类似于 [REST API](api-gateway-control-access-using-iam-policies-to-invoke-api.md) 的授权，但有以下例外情况：
+ 除了现有操作（`execute-api`、`ManageConnections`）之外，`Invoke` 操作也支持 `InvalidateCache`。`ManageConnections` 控制对 @connections API 的访问。
+ WebSocket 路由使用不同的 ARN 格式：

  ```
  arn:aws:execute-api:region:account-id:api-id/stage-name/route-key
  ```
+ `@connections` API 使用与 REST API 相同的 ARN 格式：

  ```
  arn:aws:execute-api:region:account-id:api-id/stage-name/POST/@connections
  ```

**重要**  
在使用 [IAM 授权](#apigateway-websocket-control-access-iam)时，必须使用[签名版本 4 (SigV4)](https://docs.aws.amazon.com/IAM/latest/UserGuide/create-signed-request.html) 对请求进行签名。

例如，您可以为客户端设置以下策略。此示例能让每个人为 `Invoke` 阶段中除密钥路由之外的所有路由发送消息 (`prod`)，并针对所有阶段阻止每个人将消息发送回连接的客户端 (`ManageConnections`)。

------
#### [ JSON ]

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "execute-api:Invoke"
            ],
            "Resource": [
                "arn:aws:execute-api:us-east-1:111122223333:api-id/prod/*"
            ]
        },
        {
            "Effect": "Deny",
            "Action": [
                "execute-api:Invoke"
            ],
            "Resource": [
                "arn:aws:execute-api:us-east-1:111122223333:api-id/prod/secret"
            ]
        },
        {
            "Effect": "Deny",
            "Action": [
                "execute-api:ManageConnections"
            ],
            "Resource": [
                "arn:aws:execute-api:us-east-1:111122223333:api-id/*"
            ]
        }
    ]
}
```

------

# 利用 AWS Lambda REQUEST 授权方来控制对 WebSocket API 的访问
<a name="apigateway-websocket-api-lambda-auth"></a>

WebSocket API 中的 Lambda 授权方函数类似于 [REST API](apigateway-use-lambda-authorizer.md#api-gateway-lambda-authorizer-lambda-function-create) 的授权方函数，但有以下例外情况：
+  您只能对 `$connect` 路由使用 Lambda 授权方函数。
+ 您不能使用路径变量 (`event.pathParameters`)，因为路径是固定的。
+ `event.methodArn` 与 REST API 等效变量不同，因为它没有 HTTP 方法。如果是 `$connect`，则 `methodArn` 以 `"$connect"` 结尾：

  ```
  arn:aws:execute-api:region:account-id:api-id/stage-name/$connect
  ```
+ `event.requestContext` 中的上下文变量与 REST API 的上下文变量不同。

 以下示例显示了适用于 WebSocket API 的 `REQUEST` 授权方的输入：

```
{
    "type": "REQUEST",
    "methodArn": "arn:aws:execute-api:us-east-1:123456789012:abcdef123/default/$connect",
    "headers": {
        "Connection": "upgrade",
        "content-length": "0",
        "HeaderAuth1": "headerValue1",
        "Host": "abcdef123.execute-api.us-east-1.amazonaws.com",
        "Sec-WebSocket-Extensions": "permessage-deflate; client_max_window_bits",
        "Sec-WebSocket-Key": "...",
        "Sec-WebSocket-Version": "13",
        "Upgrade": "websocket",
        "X-Amzn-Trace-Id": "...",
        "X-Forwarded-For": "...",
        "X-Forwarded-Port": "443",
        "X-Forwarded-Proto": "https"
    },
    "multiValueHeaders": {
        "Connection": [
            "upgrade"
        ],
        "content-length": [
            "0"
        ],
        "HeaderAuth1": [
            "headerValue1"
        ],
        "Host": [
            "abcdef123.execute-api.us-east-1.amazonaws.com"
        ],
        "Sec-WebSocket-Extensions": [
            "permessage-deflate; client_max_window_bits"
        ],
        "Sec-WebSocket-Key": [
            "..."
        ],
        "Sec-WebSocket-Version": [
            "13"
        ],
        "Upgrade": [
            "websocket"
        ],
        "X-Amzn-Trace-Id": [
            "..."
        ],
        "X-Forwarded-For": [
            "..."
        ],
        "X-Forwarded-Port": [
            "443"
        ],
        "X-Forwarded-Proto": [
            "https"
        ]
    },
    "queryStringParameters": {
        "QueryString1": "queryValue1"
    },
    "multiValueQueryStringParameters": {
        "QueryString1": [
            "queryValue1"
        ]
    },
    "stageVariables": {},
    "requestContext": {
        "routeKey": "$connect",
        "eventType": "CONNECT",
        "extendedRequestId": "...",
        "requestTime": "19/Jan/2023:21:13:26 +0000",
        "messageDirection": "IN",
        "stage": "default",
        "connectedAt": 1674162806344,
        "requestTimeEpoch": 1674162806345,
        "identity": {
            "sourceIp": "..."
        },
        "requestId": "...",
        "domainName": "abcdef123.execute-api.us-east-1.amazonaws.com",
        "connectionId": "...",
        "apiId": "abcdef123"
    }
}
```

以下示例 Lambda 授权方函数是[其他 Lambda 授权方函数示例](apigateway-use-lambda-authorizer.md#api-gateway-lambda-authorizer-lambda-function-create)中 REST API 的 Lambda 授权方函数的 WebSocket 版本：

------
#### [ Node.js ]

```
   // A simple REQUEST authorizer example to demonstrate how to use request 
   // parameters to allow or deny a request. In this example, a request is  
   // authorized if the client-supplied HeaderAuth1 header and QueryString1 query parameter
   // in the request context match the specified values of
   // of 'headerValue1' and 'queryValue1' respectively.
            export const handler = function(event, context, callback) {
    console.log('Received event:', JSON.stringify(event, null, 2));

   // Retrieve request parameters from the Lambda function input:
   var headers = event.headers;
   var queryStringParameters = event.queryStringParameters;
   var stageVariables = event.stageVariables;
   var requestContext = event.requestContext;
       
   // Parse the input for the parameter values
   var tmp = event.methodArn.split(':');
   var apiGatewayArnTmp = tmp[5].split('/');
   var awsAccountId = tmp[4];
   var region = tmp[3];
   var ApiId = apiGatewayArnTmp[0];
   var stage = apiGatewayArnTmp[1];
   var route = apiGatewayArnTmp[2];
       
   // Perform authorization to return the Allow policy for correct parameters and 
   // the 'Unauthorized' error, otherwise.
   var authResponse = {};
   var condition = {};
    condition.IpAddress = {};
    
   if (headers.HeaderAuth1 === "headerValue1"
       && queryStringParameters.QueryString1 === "queryValue1") {
        callback(null, generateAllow('me', event.methodArn));
    }  else {
        callback(null, generateDeny('me', event.methodArn)); 
    }
}
    
// Helper function to generate an IAM policy
var generatePolicy = function(principalId, effect, resource) {
   // Required output:
   var authResponse = {};
    authResponse.principalId = principalId;
   if (effect && resource) {
       var policyDocument = {};
        policyDocument.Version = '2012-10-17		 	 	 '; // default version
       policyDocument.Statement = [];
       var statementOne = {};
        statementOne.Action = 'execute-api:Invoke'; // default action
       statementOne.Effect = effect;
        statementOne.Resource = resource;
        policyDocument.Statement[0] = statementOne;
        authResponse.policyDocument = policyDocument;
    }
   // Optional output with custom properties of the String, Number or Boolean type.
   authResponse.context = {
       "stringKey": "stringval",
       "numberKey": 123,
       "booleanKey": true
    };
   return authResponse;
}
    
var generateAllow = function(principalId, resource) {
   return generatePolicy(principalId, 'Allow', resource);
}
    
var generateDeny = function(principalId, resource) {
   return generatePolicy(principalId, 'Deny', resource);
}
```

------
#### [ Python ]

```
# A simple REQUEST authorizer example to demonstrate how to use request
# parameters to allow or deny a request. In this example, a request is
# authorized if the client-supplied HeaderAuth1 header and QueryString1 query parameter
# in the request context match the specified values of
# of 'headerValue1' and 'queryValue1' respectively.

import json


def lambda_handler(event, context):
    print(event)

    # Retrieve request parameters from the Lambda function input:
    headers = event['headers']
    queryStringParameters = event['queryStringParameters']
    stageVariables = event['stageVariables']
    requestContext = event['requestContext']

    # Parse the input for the parameter values
    tmp = event['methodArn'].split(':')
    apiGatewayArnTmp = tmp[5].split('/')
    awsAccountId = tmp[4]
    region = tmp[3]
    ApiId = apiGatewayArnTmp[0]
    stage = apiGatewayArnTmp[1]
    route = apiGatewayArnTmp[2]

    # Perform authorization to return the Allow policy for correct parameters
    # and the 'Unauthorized' error, otherwise.

    authResponse = {}
    condition = {}
    condition['IpAddress'] = {}

    if (headers['HeaderAuth1'] ==
            "headerValue1" and queryStringParameters["QueryString1"] == "queryValue1"):
        response = generateAllow('me', event['methodArn'])
        print('authorized')
        return json.loads(response)
    else:
        response = generateDeny('me', event['methodArn'])
        print('unauthorized')
        return json.loads(response)

    # Help function to generate IAM policy


def generatePolicy(principalId, effect, resource):
    authResponse = {}
    authResponse['principalId'] = principalId
    if (effect and resource):
        policyDocument = {}
        policyDocument['Version'] = '2012-10-17		 	 	 '
        policyDocument['Statement'] = []
        statementOne = {}
        statementOne['Action'] = 'execute-api:Invoke'
        statementOne['Effect'] = effect
        statementOne['Resource'] = resource
        policyDocument['Statement'] = [statementOne]
        authResponse['policyDocument'] = policyDocument

    authResponse['context'] = {
        "stringKey": "stringval",
        "numberKey": 123,
        "booleanKey": True
    }

    authResponse_JSON = json.dumps(authResponse)

    return authResponse_JSON


def generateAllow(principalId, resource):
    return generatePolicy(principalId, 'Allow', resource)


def generateDeny(principalId, resource):
    return generatePolicy(principalId, 'Deny', resource)
```

------

要将前面的 Lambda 函数配置为 WebSocket API 的 `REQUEST` 授权方函数，请遵循与 [REST API](configure-api-gateway-lambda-authorization.md#configure-api-gateway-lambda-authorization-with-console) 相同的过程。

要将 `$connect` 路由配置为在控制台中使用此 Lambda 授权方，请选择或创建 `$connect` 路由。在**路由请求设置**部分中，选择**编辑**。在**授权**下拉菜单中选择您的授权方，然后选择**保存更改**。

要测试授权方，您将需要创建一个新连接。在 `$connect` 中更改授权方不会影响已连接的客户端。当您连接到 WebSocket API 时，需要为任何已配置的身份源提供值。例如，您可以通过使用 `wscat` 发送有效的查询字符串和标头进行连接，如以下示例所示：

```
wscat -c 'wss://myapi.execute-api.us-east-1.amazonaws.com/beta?QueryString1=queryValue1' -H HeaderAuth1:headerValue1
```

如果您尝试在没有有效身份值的情况下进行连接，您将收到 `401` 响应：

```
wscat -c wss://myapi.execute-api.us-east-1.amazonaws.com/beta
error: Unexpected server response: 401
```

# API Gateway 中 WebSocket API 的集成
<a name="apigateway-websocket-api-integrations"></a>

设置 API 路由之后，您必须将其与后端中的端点集成。后端端点也称为集成端点，它可以是 Lambda 函数、HTTP 端点或AWS服务操作。API 集成有一个集成请求和一个集成响应。

在本节中，您将了解如何为 WebSocket API 设置集成请求和集成响应。

**Topics**
+ [在 API Gateway 中设置 WebSocket API 集成请求](apigateway-websocket-api-integration-requests.md)
+ [在 API Gateway 中设置 WebSocket API 集成响应](apigateway-websocket-api-integration-responses.md)

# 在 API Gateway 中设置 WebSocket API 集成请求
<a name="apigateway-websocket-api-integration-requests"></a>

设置集成请求涉及以下内容：
+ 选择要集成到后端的路由键。
+ 指定要调用的后端端点。WebSocket API 支持以下集成类型：
  + `AWS_PROXY`
  + `AWS`
  + `HTTP_PROXY`
  + `HTTP`
  + `MOCK`

  有关集成类型的更多信息，请参阅《API Gateway V2 REST API》中的 [IntegrationType](https://docs.aws.amazon.com/apigatewayv2/latest/api-reference/apis-apiid-integrations-integrationid.html#apis-apiid-integrations-integrationid-prop-integration-integrationtype)。
+ 通过指定一个或多个请求模板，配置如何根据需要将路径请求数据转换为集成请求数据。

## 使用 API Gateway 控制台设置 WebSocket API 集成请求
<a name="apigateway-websocket-api-integration-request-using-console"></a>

**使用 API Gateway 控制台向 WebSocket API 中的路由添加集成请求**

1. 登录到 API Gateway 控制台，选择 API，然后选择**路由**。

1. 在**路由**中，选择所需路由。

1. 选择**集成请求**选项卡，然后在**集成请求设置**部分中，选择**编辑**。

1. 对于**集成类型**，选择下列选项之一：
   + 仅当您的 API 将与您已在此账户或其它账户中创建的 AWS Lambda 函数集成时，才选择 **Lambda 函数**。

     要在 AWS Lambda 中创建新的 Lambda 函数，要为 Lambda 函数设置资源权限，或者要执行任何其他 Lambda 服务操作，请改为选择 **AWS 服务**。
   + 如果您的 API 将与现有 HTTP 端点集成，请选择 **HTTP**。有关更多信息，请参阅 [针对 API Gateway 中的 REST API 的 HTTP 集成](setup-http-integrations.md)。
   + 如果要直接从 API Gateway 生成 API 响应，而无需集成后端，请选择**模拟**。有关更多信息，请参阅 [针对 API Gateway 中的 REST API 的模拟集成](how-to-mock-integration.md)。
   + 如果您的 API 将与某项 AWS 服务集成，则选择 **AWS 服务**。
   + 如果您的 API 将使用 `VpcLink` 作为私有集成端点，请选择 **VPC 链接**。有关更多信息，请参阅 [设置私有集成](set-up-private-integration.md)。

1. 如果您选择 **Lambda 函数**，请执行以下操作：

   1. 对于**使用 Lambda 代理集成**，如果您打算使用 [Lambda 代理集成](set-up-lambda-proxy-integrations.md#api-gateway-create-api-as-simple-proxy)或[跨账户 Lambda 代理集成](apigateway-cross-account-lambda-integrations.md)，请选中此复选框。

   1. 对于 **Lambda 函数**，请通过以下方式之一指定函数：
      + 如果您的 Lambda 函数在同一账户中，请输入函数名称，然后从下拉列表中选择函数。
**注意**  
函数名称可以包含（可选）其别名或版本规范，如在 `HelloWorld`、`HelloWorld:1` 或 `HelloWorld:alpha` 中。
      + 如果该函数位于不同账户，请输入该函数的 ARN。

   1. 要使用默认超时值 29 秒，请保持**默认超时**处于开启状态。要设置自定义超时，请选择**默认超时**，然后输入一个介于 `50` 到 `29000` 毫秒之间的超时值。

1. 如果您选择了 **HTTP**，请遵循[使用 API Gateway 控制台设置 API 集成请求](how-to-method-settings-console.md)的步骤 4 中的说明。

1. 如果您选择了**模拟**，请继续执行**请求模板**步骤。

1. 如果您选择了 **AWS 服务**，请遵循[使用 API Gateway 控制台设置 API 集成请求](how-to-method-settings-console.md)的步骤 6 中的说明操作。

1. 如果您选择了 **VPC 链接**，请执行以下操作：

   1. 对于 **VPC 代理集成**，如果要将请求通过代理连接到 `VPCLink` 的端点，请选中该复选框。

   1. 对于 **HTTP 方法**，选择与 HTTP 后端中的方法最匹配的 HTTP 方法类型。

   1. 从 **VPC 链接**下拉列表中，选择一个 VPC 链接。您可以选择 `[Use Stage Variables]` 并在列表下方的文本框中输入 **\$1\$1stageVariables.vpcLinkId\$1**。

      您可以在将 API 部署到阶段之后定义 `vpcLinkId` 阶段变量，并将其值设置为 `VpcLink` 的 ID。

   1. 对于**端点 URL**，请输入您希望此集成使用的 HTTP 后端的 URL。

   1. 要使用默认超时值 29 秒，请保持**默认超时**处于开启状态。要设置自定义超时，请选择**默认超时**，然后输入一个介于 `50` 到 `29000` 毫秒之间的超时值。

1. 选择 **Save changes（保存更改）**。

1. 在**请求模板**下方，执行以下操作：

   1. 要输入**模板选择表达式**，请在**请求模板**下选择**编辑**。

   1. 输入**模板选择表达式**。使用 API Gateway 在消息负载中查找的表达式。如果找到，则对其进行评估，结果是模板键值，用于选择要应用于消息负载中的数据的数据映射模板。您将在下一步中创建数据映射模板。选择**编辑**以保存所做更改。

   1. 选择**创建模板**以创建数据映射模板。对于**模板密钥**，输入一个模板密钥值，用于选择要应用于消息负载中的数据的数据映射模板。然后，输入映射模板。选择**创建模板**。

      有关模板选择表达式的信息，请参阅[模板选择表达式](websocket-api-data-transformations.md#apigateway-websocket-api-template-selection-expressions)。

## 使用 AWS CLI 设置集成请求
<a name="apigateway-websocket-api-integration-request-using-awscli"></a>

您可以使用 AWS CLI 为 WebSocket API 中的路由设置集成请求，如以下示例所示（这将创建模拟集成）：

1. 使用以下内容创建名为 `integration-params.json` 的文件：

   ```
   {"PassthroughBehavior": "WHEN_NO_MATCH", "TimeoutInMillis": 29000, "ConnectionType": "INTERNET", "RequestTemplates": {"application/json": "{\"statusCode\":200}"}, "IntegrationType": "MOCK"}
   ```

1. 使用以下 [create-integration](https://docs.aws.amazon.com/cli/latest/reference/apigatewayv2/create-integration.html) 命令创建模拟集成。

   ```
   aws apigatewayv2 --region us-east-1 create-integration --api-id aabbccddee --cli-input-json file://integration-params.json
   ```

   输出将与以下内容类似：

   ```
   {
       "PassthroughBehavior": "WHEN_NO_MATCH",
       "TimeoutInMillis": 29000,
       "ConnectionType": "INTERNET",
       "IntegrationResponseSelectionExpression": "${response.statuscode}",
       "RequestTemplates": {
           "application/json": "{\"statusCode\":200}"
       },
       "IntegrationId": "0abcdef",
       "IntegrationType": "MOCK"
   }
   ```

或者，您可以使用 AWS CLI 为代理集成设置集成请求。

1. 在 Lambda 控制台中创建 Lambda 函数，并为其提供基本的 Lambda 执行角色。

1. 使用以下 [create-integration](https://docs.aws.amazon.com/cli/latest/reference/apigatewayv2/create-integration.html) 命令创建集成。

   ```
   aws apigatewayv2 create-integration --api-id aabbccddee --integration-type AWS_PROXY --integration-method POST --integration-uri arn:aws:apigateway:us-east-1:lambda:path/2015-03-31/functions/arn:aws:lambda:us-east-1:123412341234:function:simpleproxy-echo-e2e/invocations
   ```

输出将与以下内容类似：

```
{
    "PassthroughBehavior": "WHEN_NO_MATCH",
    "IntegrationMethod": "POST",
    "TimeoutInMillis": 29000,
    "ConnectionType": "INTERNET",
    "IntegrationUri": "arn:aws:apigateway:us-east-1:lambda:path/2015-03-31/functions/arn:aws:lambda:us-east-1:123412341234:function:simpleproxy-echo-e2e/invocations",
    "IntegrationId": "abcdefg",
    "IntegrationType": "AWS_PROXY"
}
```

## 适用于 WebSocket API 的代理集成的 Lambda 函数的输入格式
<a name="api-gateway-simple-proxy-for-lambda-input-format-websocket"></a>

使用 Lambda 代理集成，API Gateway 可以将整个客户端请求映射到后端 Lambda 函数的输入 `event` 参数：以下示例显示了 API Gateway 发送到 Lambda 代理集成的 `$connect` 路由中输入事件和 `$disconnect` 路由中输入事件的结构。

------
#### [ Input from the \$1connect route ]

```
{
    headers: {
      Host: 'abcd123.execute-api.us-east-1.amazonaws.com',
      'Sec-WebSocket-Extensions': 'permessage-deflate; client_max_window_bits',
      'Sec-WebSocket-Key': '...',
      'Sec-WebSocket-Version': '13',
      'X-Amzn-Trace-Id': '...',
      'X-Forwarded-For': '192.0.2.1',
      'X-Forwarded-Port': '443',
      'X-Forwarded-Proto': 'https'
    },
    multiValueHeaders: {
      Host: [ 'abcd123.execute-api.us-east-1.amazonaws.com' ],
      'Sec-WebSocket-Extensions': [ 'permessage-deflate; client_max_window_bits' ],
      'Sec-WebSocket-Key': [ '...' ],
      'Sec-WebSocket-Version': [ '13' ],
      'X-Amzn-Trace-Id': [ '...' ],
      'X-Forwarded-For': [ '192.0.2.1' ],
      'X-Forwarded-Port': [ '443' ],
      'X-Forwarded-Proto': [ 'https' ]
    },
    requestContext: {
      routeKey: '$connect',
      eventType: 'CONNECT',
      extendedRequestId: 'ABCD1234=',
      requestTime: '09/Feb/2024:18:11:43 +0000',
      messageDirection: 'IN',
      stage: 'prod',
      connectedAt: 1707502303419,
      requestTimeEpoch: 1707502303420,
      identity: { sourceIp: '192.0.2.1' },
      requestId: 'ABCD1234=',
      domainName: 'abcd1234.execute-api.us-east-1.amazonaws.com',
      connectionId: 'AAAA1234=',
      apiId: 'abcd1234'
    },
    isBase64Encoded: false
  }
```

------
#### [ Input from the \$1disconnect route ]

```
{
    headers: {
      Host: 'abcd1234.execute-api.us-east-1.amazonaws.com',
      'x-api-key': '',
      'X-Forwarded-For': '',
      'x-restapi': ''
    },
    multiValueHeaders: {
      Host: [ 'abcd1234.execute-api.us-east-1.amazonaws.com' ],
      'x-api-key': [ '' ],
      'X-Forwarded-For': [ '' ],
      'x-restapi': [ '' ]
    },
    requestContext: {
      routeKey: '$disconnect',
      disconnectStatusCode: 1005,
      eventType: 'DISCONNECT',
      extendedRequestId: 'ABCD1234=',
      requestTime: '09/Feb/2024:18:23:28 +0000',
      messageDirection: 'IN',
      disconnectReason: 'Client-side close frame status not set',
      stage: 'prod',
      connectedAt: 1707503007396,
      requestTimeEpoch: 1707503008941,
      identity: { sourceIp: '192.0.2.1' },
      requestId: 'ABCD1234=',
      domainName: 'abcd1234.execute-api.us-east-1.amazonaws.com',
      connectionId: 'AAAA1234=',
      apiId: 'abcd1234'
    },
    isBase64Encoded: false
  }
```

------

# 在 API Gateway 中设置 WebSocket API 集成响应
<a name="apigateway-websocket-api-integration-responses"></a>

下一节简要概述了 WebSocket API 的集成响应，以及如何为 WebSocket API 设置集成响应。

**Topics**
+ [集成响应概述](#apigateway-websocket-api-integration-response-overview)
+ [双向通信的集成响应](#apigateway-websocket-api-integration-response-for-two-way-communication)
+ [使用 API Gateway 控制台设置集成响应](#apigateway-websocket-api-integration-response-using-console)
+ [使用 AWS CLI 设置集成响应](#apigateway-websocket-api-integration-response-using-awscli)

## 集成响应概述
<a name="apigateway-websocket-api-integration-response-overview"></a>

API Gateway 的集成响应是一种用于对后端服务的响应进行建模和处理的方法。REST API 与 WebSocket API 集成响应的设置存在一些差别，但从概念上讲，行为是相同的。

WebSocket 路由可以配置为双向或单向通信。
+ 当路由配置为双向通信时，集成响应能让您对返回的消息负载配置转换，类似于 REST API 的集成响应。
+ 如果路由配置为单向通信，则无论是否有任何集成响应配置，在处理消息后都不会通过 WebSocket 通道返回响应。

 除非您设置了路由响应，否则 API Gateway 不会将后端响应传递给路由响应。要了解有关设置路径响应的信息，请参阅 [为 API Gateway 中的 WebSocket API 设置路由响应](apigateway-websocket-api-route-response.md)。

## 双向通信的集成响应
<a name="apigateway-websocket-api-integration-response-for-two-way-communication"></a>

集成可以分为*代理*集成和*非代理*集成。

**重要**  
对于*代理集成*，API Gateway 会自动将后端输出作为完整的负载传递给调用方。没有集成响应。

对于*非代理集成*，您必须至少设置一个集成响应：
+ 理想情况下，您的一个集成响应应该在无法进行明确的选择时是包罗万象的响应。此默认情况是通过设置 `$default` 的集成响应键来表示的。
+ 在所有其他情况下，集成响应键起正则表达式的作用。它应遵循 `"/expression/"` 格式。

对于非代理 HTTP 集成：
+ API Gateway 将尝试匹配后端响应的 HTTP 状态代码。在这种情况下，集成响应键将起正则表达式的作用。如果找不到匹配项，则会选择 `$default` 作为集成响应。
+ 如上所述，模板选择表达式的作用相同。例如：
  + `/2\d\d/`：接收并转换成功响应
  + `/4\d\d/`：接收并转换不正确的请求错误
  + `$default`：接收并转换所有意外响应

有关模板选择表达式的更多信息，请参阅 [模板选择表达式](websocket-api-data-transformations.md#apigateway-websocket-api-template-selection-expressions)。

## 使用 API Gateway 控制台设置集成响应
<a name="apigateway-websocket-api-integration-response-using-console"></a>

要使用 API Gateway 控制台为 WebSocket API 设置路由集成响应，请执行以下操作：

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

1.  选择 WebSocket API，然后选择路由。

1. 选择**集成请求**选项卡，然后在**集成响应设置**部分中，选择**创建集成响应**。

1. 对于**响应密钥**，输入一个值，该值将在评估响应选择表达式后在传出消息中的响应密钥中找到。例如，您可以输入 **/4\$1d\$1d/** 以接收和转换错误的请求错误，也可以输入 **\$1default** 以接收和转换与模板选择表达式匹配的所有响应。

1. 对于**模板选择表达式**，输入选择表达式来评估传出的消息。

1. 选择**创建响应**。

1. 您还可以定义映射模板来配置返回的消息有效负载的转换。选择**创建模板**。

1. 输入键名称。如果您选择的是默认模板选择表达式，请输入 **\$1\$1default**。

1. 对于**响应模板**，请在代码编辑器中输入您的映射模板。

1. 选择**创建模板**。

1. 选择**部署 API** 以部署您的 API。

 使用以下 [wscat](https://www.npmjs.com/package/wscat) 命令连接到您的 API。有关 `wscat` 的更多信息，请参阅 [使用 `wscat` 连接到 WebSocket API 并向其发送消息](apigateway-how-to-call-websocket-api-wscat.md)。

```
wscat -c wss://api-id.execute-api.us-east-2.amazonaws.com/test
```

 当您调用路由时，应返回消息有效负载。

## 使用 AWS CLI 设置集成响应
<a name="apigateway-websocket-api-integration-response-using-awscli"></a>

使用以下 [create-integration-response](https://docs.aws.amazon.com/cli/latest/reference/apigatewayv2/create-integration-response.html) 命令创建 `$default` 集成响应：

```
aws apigatewayv2 create-integration-response \
    --api-id vaz7da96z6 \
    --integration-id a1b2c3 \
    --integration-response-key '$default'
```

# 针对 API Gateway 中的 WebSocket API 的请求验证
<a name="websocket-api-request-validation"></a>

您可以配置 API Gateway，使其在继续集成请求之前对路由请求执行验证。如果验证失败，API Gateway 将在不调用后端的情况下使请求失败，向客户端发送“错误请求正文”网关响应，并在 CloudWatch Logs 中发布验证结果。通过这种方式使用验证可减少对 API 后端的不必要调用。

## 模型选择表达式
<a name="apigateway-websocket-api-model-selection-expressions"></a>

您可以使用模型选择表达式来动态验证同一路由中的请求。如果您为代理集成或非代理集成提供模型选择表达式，则会发生模型验证。当未找到匹配模型时，您可能需要将 `$default` 模型定义为回退。如果没有匹配模型且未定义 `$default`，则验证将失败。选择表达式类似于 `Route.ModelSelectionExpression`，并计算为 `Route.RequestModels` 的键。

当您为 WebSocket API 定义路由时，可以选择指定*模型选择表达式*。将会求解此表达式以选择在收到请求时用于正文验证的模型。表达式的求值结果为路由的 [https://docs.aws.amazon.com/apigatewayv2/latest/api-reference/apis-apiid-routes.html#apis-apiid-routes-prop-route-requestmodels](https://docs.aws.amazon.com/apigatewayv2/latest/api-reference/apis-apiid-routes.html#apis-apiid-routes-prop-route-requestmodels) 中的条目之一。

模型采用 [JSON 架构](https://datatracker.ietf.org/doc/html/draft-zyp-json-schema-04)表示，描述了请求正文的数据结构。此选择表达式的性质能让您为特定路由，在运行时动态选择要用于对照进行验证的模型。有关如何创建模型的信息，请参阅[针对 REST API 的数据模型](models-mappings-models.md)。

## 使用 API Gateway 控制台设置请求验证
<a name="apigateway-websocket-api-model-selection-expression-example"></a>

以下示例演示了如何在路径上设置请求验证。

 首先，您创建一个模型，然后创建路由。接下来，在刚创建的路径上配置请求验证。最后，您部署并测试您的 API。要完成本教程，您需要一个将 `$request.body.action` 作为路由选择表达式的 WebSocket API 和一个用于新路由的集成端点。

还需要 `wscat` 以连接到 API。有关更多信息，请参阅 [使用 `wscat` 连接到 WebSocket API 并向其发送消息](apigateway-how-to-call-websocket-api-wscat.md)。

**创建模型**

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

1. 选择 WebSocket API。

1. 在主导航窗格中，选择**模型**。

1. 选择**创建模型**。

1. 对于**名称**，请输入 **emailModel**。

1. 对于**内容类型**，输入 **application/json**。

1. 对于**模型架构**，输入以下模型：

   ```
   {
       "$schema": "http://json-schema.org/draft-04/schema#",
       "type" : "object",
       "required" : [ "address"],
       "properties" : {
           "address": {
               "type": "string"
           }
       }
   }
   ```

   此模型要求请求包含电子邮件地址。

1. 选择**保存**。

在本步骤中，您将为 WebSocket API 创建路由。

**要创建路由**

1. 在主导航窗格中，选择**路由**。

1. 选择**创建路由**。

1. 对于**路由键**，请输入 **sendMessage**。

1. 选择集成类型并指定集成端点。有关更多信息，请参阅 [API Gateway 中 WebSocket API 的集成](apigateway-websocket-api-integrations.md)。

1. 选择**创建路由**。

在此步骤中，您将为 `sendMessage` 路径设置请求验证。

**设置请求验证**

1. 在**路由请求**选项卡上的**路由请求设置**下，选择**编辑**。

1. 在**模型选择表达式**中，输入 **\$1\$1request.body.messageType\$1**。

   API Gateway 使用 `messageType` 属性来验证传入的请求。

1. 选择**添加请求模型**。

1. 对于**模型密钥**，输入 **email**。

1. 对于**模型**，选择 **emailModel**。

   API Gateway 会根据此模型验证 `messageType` 属性设置为 `email` 的传入消息。
**注意**  
如果 API Gateway 无法将模型选择表达式与模型密钥相匹配，则它会选择 `$default` 模型。如果没有 `$default` 模型，则验证将失败。对于生产 API，我们建议您创建一个 `$default` 模型。

1. 选择**保存更改**。

在本步骤中，您将部署并测试您的 API。

**部署和测试您的 API**

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

1. 从下拉列表中选择所需的阶段，或输入新阶段的名称。

1. 选择**部署**。

1. 在主导航窗格中，选择**阶段**。

1. 复制 API 的 WebSocket URL。该 URL 应类似于 `wss://abcdef123.execute-api.us-east-2.amazonaws.com/production`。

1. 打开一个新终端，并使用以下参数运行 **wscat** 命令。

   ```
   wscat -c wss://abcdef123.execute-api.us-west-2.amazonaws.com/production
   ```

   ```
   Connected (press CTRL+C to quit)
   ```

1. 使用以下命令来测试您的 API：

   ```
   {"action": "sendMessage", "messageType": "email"}
   ```

   ```
   {"message": "Invalid request body", "connectionId":"ABCD1=234", "requestId":"EFGH="}
   ```

   API Gateway 将使请求失败。

   使用下一个命令向您的 API 发送有效的请求。

   ```
   {"action": "sendMessage", "messageType": "email", "address": "mary_major@example.com"}
   ```

# 针对 API Gateway 中的 WebSocket API 的数据转换
<a name="websocket-api-data-transformations"></a>

在 API Gateway 中，WebSocket API 的方法请求采用的负载格式可能与后端所需的相应集成请求负载的格式不同。同样，后端返回的集成响应负载可能不同于前端希望的方法响应负载。

API Gateway 支持您使用映射模板转换，来将有效载荷从方法请求映射到相应的集成请求，以及从集成响应映射到相应的方法响应。您可以创建映射模板并指定模板选择表达式，来确定执行必要的数据转换时所用的模板。

您可以使用数据映射将[路由请求](api-gateway-basic-concept.md#apigateway-definition-route-request)中的数据映射到后端集成。要了解更多信息，请参阅“[为 API Gateway 中的 WebSocket API 设置数据映射](websocket-api-data-mapping.md)”。

## 映射模板和模型
<a name="apigateway-websocket-api-mapping-templats-and-models"></a>

 *映射模板*是一个用 [Velocity 模板语言 (VTL)](https://velocity.apache.org/engine/devel/vtl-reference.html) 表示的脚本，应用于使用 [JSONPath 表达式](https://goessner.net/articles/JsonPath/)的负载。有关 API Gateway 映射模板的更多信息，请参阅[API Gateway 中 REST API 的映射模板转换](models-mappings.md)。

负载可以拥有符合 [JSON 架构草案 4](https://datatracker.ietf.org/doc/html/draft-zyp-json-schema-04) 的*数据模型*。您不必定义模型来创建映射模板。但是，模型可以帮助您创建模板，因为 API Gateway 根据提供的模型生成模板蓝图。有关 API Gateway 模型的更多信息，请参阅[针对 REST API 的数据模型](models-mappings-models.md)。

## 模板选择表达式
<a name="apigateway-websocket-api-template-selection-expressions"></a>

要使用映射模板转换负载，请在[集成请求](apigateway-websocket-api-integration-requests.md)或[集成响应](apigateway-websocket-api-integration-responses.md)中指定 WebSocket API 模板选择表达式。将会求解此表达式以确定用于将请求正文转换为集成请求正文（通过输入模板）或将响应正文转换为路由响应正文（通过输出模板）的输入或输出模板（如果有）。

`Integration.TemplateSelectionExpression` 支持 `${request.body.jsonPath}` 和静态值。

`IntegrationResponse.TemplateSelectionExpression` 支持 `${request.body.jsonPath}`、`${integration.response.statuscode}`、`${integration.response.header.headerName}`、`${integration.response.multivalueheader.headerName}` 和静态值。

## 集成响应选择表达式
<a name="apigateway-websocket-api-integration-response-selection-expressions"></a>

当您为 WebSocket API [设置集成响应](apigateway-websocket-api-integration-responses.md)时，您可以指定（可选）集成响应选择表达式。此表达式确定在集成返回时应选择什么 `[https://docs.aws.amazon.com/apigatewayv2/latest/api-reference/apis-apiid-integrations-integrationid-integrationresponses-integrationresponseid.html](https://docs.aws.amazon.com/apigatewayv2/latest/api-reference/apis-apiid-integrations-integrationid-integrationresponses-integrationresponseid.html)`。此表达式的值当前受 API Gateway 限制，定义如下。认识到此表达式只与*非代理集成*相关；代理集成无需建模或修改便会将响应负载传递回调用方。

与前面的其他选择表达式不同，此表达式当前支持*模式匹配* 格式。表达式应该用正斜杠包装起来。

目前，该值是固定的，具体取决于 `[https://docs.aws.amazon.com/apigatewayv2/latest/api-reference/apis-apiid-integrations-integrationid.html#apis-apiid-integrations-integrationid-prop-integration-integrationtype](https://docs.aws.amazon.com/apigatewayv2/latest/api-reference/apis-apiid-integrations-integrationid.html#apis-apiid-integrations-integrationid-prop-integration-integrationtype)`：
+ 对于基于 Lambda 的集成，它是 `$integration.response.body.errorMessage`。
+ 对于 `HTTP` 和 `MOCK` 集成，它是 `$integration.response.statuscode`。
+ 对于 `HTTP_PROXY` 和 `AWS_PROXY`，不会使用此表达式，因为您请求将负载传递给调用方。

# 为 API Gateway 中的 WebSocket API 设置数据映射
<a name="websocket-api-data-mapping"></a>

*数据映射* 使您能够将数据从[路由请求](api-gateway-basic-concept.md#apigateway-definition-route-request)映射到后端集成。

**注意**  
 中不支持 WebSocket API 的数据映射AWS 管理控制台 必须使用 AWS CLI、AWS CloudFormation 或开发工具包配置数据映射。

**Topics**
+ [将路由请求数据映射至集成请求参数](#websocket-mapping-request-parameters)
+ [示例](#websocket-data-mapping-examples)

## 将路由请求数据映射至集成请求参数
<a name="websocket-mapping-request-parameters"></a>

可以从任何定义的路由请求参数、请求正文、[`context` 或](api-gateway-mapping-template-reference.md#context-variable-reference) [`stage`](api-gateway-mapping-template-reference.md#stagevariables-template-reference) 变量以及静态值映射集成请求参数。

下表显示集成请求数据映射表达式。在此表中，*`PARAM_NAME`* 是给定参数类型的路由请求参数的名称。它必须匹配正则表达式 `'^[a-zA-Z0-9._$-]+$]'`。*JSONPath\$1EXPRESSION* 是请求正文的 JSON 字段的 JSONPath 表达式。


| 映射的数据来源 | 映射表达式 | 
| --- | --- | 
| 请求查询字符串（仅对于 \$1connect 路由才支持） | route.request.querystring.PARAM\$1NAME | 
| 请求标头（仅对于 \$1connect 路由才支持） | route.request.header.PARAM\$1NAME | 
| 多值请求查询字符串（仅对于 \$1connect 路由才支持） | route.request.multivaluequerystring.PARAM\$1NAME | 
| 多值请求标头（仅对于 \$1connect 路由才支持） | route.request.multivalueheader.PARAM\$1NAME | 
| 请求正文 | route.request.body.JSONPath\$1EXPRESSION | 
| 阶段变量 | stageVariables.VARIABLE\$1NAME | 
| 上下文变量 | context.VARIABLE\$1NAME，必须为[受支持的上下文变量](api-gateway-mapping-template-reference.md#context-variable-reference)之一。 | 
| 静态值 | 'STATIC\$1VALUE'。STATIC\$1VALUE 为字符串文本值，必须括在单引号内。 | 

创建数据映射时，使用 AWS CLI 可确保遵循正确的格式，以便在 AWS CLI 中将文本与字符串结合使用。有关更多信息，请参阅《AWS Command Line Interface 用户指南》**中的[在 AWS CLI 中将引号和文本与字符串结合使用](https://docs.aws.amazon.com/cli/latest/userguide/cli-usage-parameters-quoting-strings.html)。

## 示例
<a name="websocket-data-mapping-examples"></a>

以下 AWS CLI 示例配置数据映射。有关示例 CloudFormation 模板，请参阅 [samples/websocket-data-mapping.zip](samples/websocket-data-mapping.zip)。

### 将客户端的 connectionId 映射到集成请求中的标头
<a name="websocket-data-mapping-examples.connectionId"></a>

以下 [update-integration](https://docs.aws.amazon.com/cli/latest/reference/apigatewayv2/update-integration.html) 命令将客户端的 `connectionId` 映射到发送给后端集成的请求中的 `connectionId` 标头。

```
aws apigatewayv2 update-integration \
    --integration-id abc123 \
    --api-id a1b2c3d4 \ 
    --request-parameters 'integration.request.header.connectionId'='context.connectionId'
```

### 将查询字符串参数映射到集成请求中的标头
<a name="websocket-data-mapping-examples.querystring"></a>

以下示例将 `authToken` 查询字符串参数映射到集成请求中的 `authToken` 标头。

1. 使用以下 [update-route](https://docs.aws.amazon.com/cli/latest/reference/apigatewayv2/update-route.html) 命令，将 `authToken` 查询字符串参数添加到路由的请求参数中。

   ```
   aws apigatewayv2 update-route --route-id 0abcdef \
       --api-id a1b2c3d4 \
       --request-parameters '{"route.request.querystring.authToken": {"Required": false}}'
   ```

1.  使用以下 [update-integration](https://docs.aws.amazon.com/cli/latest/reference/apigatewayv2/update-integration.html) 命令，将查询字符串参数映射到发送给后端集成的请求中的 `authToken` 标头。

   ```
   aws apigatewayv2 update-integration \
       --integration-id abc123 \
       --api-id a1b2c3d4 \
       --request-parameters 'integration.request.header.authToken'='route.request.querystring.authToken'
   ```

1. （可选）如有必要，请使用以下 [delete-route-request-parameter](https://docs.aws.amazon.com/cli/latest/reference/apigatewayv2/delete-route-request-parameter.html)，从路由的请求参数中删除 `authToken` 查询字符串参数。

   ```
   aws apigatewayv2 delete-route-request-parameter \
       --route-id 0abcdef \
       --api-id a1b2c3d4 \
       --request-parameter-key 'route.request.querystring.authToken'
   ```

# API Gateway 的 WebSocket API 映射模板参考
<a name="apigateway-websocket-api-mapping-template-reference"></a>

本节总结了 API Gateway 中 WebSocket API 当前支持的变量集。


| 参数 | 说明 | 
| --- | --- | 
| \$1context.connectionId |  连接的唯一 ID，可用于对客户端进行回调。  | 
| \$1context.connectedAt |  [Epoch](https://en.wikipedia.org/wiki/Unix_time) 格式的连接时间。  | 
| \$1context.domainName |  WebSocket API 的域名。这可用于对客户端进行回调（而不是硬编码值）。  | 
| \$1context.eventType |  事件类型：`CONNECT`、`MESSAGE` 或 `DISCONNECT`。  | 
| \$1context.messageId |  消息的唯一服务器端 ID。仅当 `$context.eventType` 为 `MESSAGE` 时才可用。  | 
| \$1context.routeKey |  选定的路由键。  | 
| \$1context.requestId |  与 `$context.extendedRequestId` 相同。  | 
| \$1context.extendedRequestId | 为 API 调用自动生成的 ID，其中包含用于调试/故障排除的更有用的信息。 | 
| \$1context.apiId |  API Gateway 分配给您的 API 的标识符。  | 
| \$1context.authorizer.principalId |  与由客户端发送的令牌关联并从 API Gateway Lambda 授权方（以前称为自定义授权方）Lambda 函数返回的委托人用户标识。  | 
| \$1context.authorizer.property |  从 API Gateway Lambda 授权方函数返回的 `context` 映射的指定键/值对的字符串化值。例如，如果授权方返回以下 `context` 映射： <pre>"context" : {<br />  "key": "value",<br />  "numKey": 1,<br />  "boolKey": true<br />}</pre> 调用 `$context.authorizer.key` 将返回 `"value"` 字符串，调用 `$context.authorizer.numKey` 将返回 `"1"` 字符串，而调用 `$context.authorizer.boolKey` 将返回 `"true"` 字符串。  | 
| \$1context.error.messageString | \$1context.error.message 的带引号的值，即 "\$1context.error.message"。 | 
| \$1context.error.validationErrorString |  包含详细验证错误消息的字符串。  | 
| \$1context.identity.accountId |  与请求关联的 AWS 账户 ID。  | 
| \$1context.identity.apiKey |  API 所有者密钥与启用密钥的 API 请求关联。  | 
| \$1context.identity.apiKeyId | API 密钥 ID 与启用密钥的 API 请求关联 | 
| \$1context.identity.caller |  发出请求的调用方的委托人标识符。  | 
| \$1context.identity.cognitoAuthenticationProvider |  发出请求的调用方使用的所有 Amazon Cognito 身份验证提供程序的逗号分隔列表。仅当使用 Amazon Cognito 凭证对请求签名时才可用。 例如，对于 Amazon Cognito 身份池中的身份，`cognito-idp. region.amazonaws.com/user_pool_id,cognito-idp.region.amazonaws.com/user_pool_id:CognitoSignIn:token subject claim` 有关更多信息，请参阅 *Amazon Cognito 开发人员指南* 中的[使用联合身份](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-identity.html)。 | 
| \$1context.identity.cognitoAuthenticationType |  发出请求的调用方的 Amazon Cognito 身份验证类型。仅当使用 Amazon Cognito 凭证对请求签名时才可用。可能的值包括经过身份验证的身份的 `authenticated` 和未经身份验证的身份的 `unauthenticated`。 | 
| \$1context.identity.cognitoIdentityId |  发出请求的调用方的 Amazon Cognito 身份 ID。仅当使用 Amazon Cognito 凭证对请求签名时才可用。  | 
| \$1context.identity.cognitoIdentityPoolId |  发出请求的调用方的 Amazon Cognito 身份池 ID。仅当使用 Amazon Cognito 凭证对请求签名时才可用。  | 
| \$1context.identity.sourceIp |  向 API Gateway 终端节点发出请求的即时 TCP 连接的源 IP 地址。  | 
| \$1context.identity.user |  发出请求的用户的委托人标识符。  | 
| \$1context.identity.userAgent |  API 调用方的用户代理。  | 
| \$1context.identity.userArn |  身份验证后标识的有效用户的 Amazon Resource Name (ARN)。  | 
| \$1context.requestTime | [CLF](https://httpd.apache.org/docs/current/logs.html#common) 格式的请求时间 (dd/MMM/yyyy:HH:mm:ss \$1-hhmm)。 | 
| \$1context.requestTimeEpoch | [Epoch](https://en.wikipedia.org/wiki/Unix_time) 格式的请求时间，以毫秒为单位。 | 
| \$1context.stage |  API 调用的部署阶段（例如测试或生产）。  | 
| \$1context.status |  响应状态。  | 
| \$1input.body | 以字符串形式返回原始负载。 | 
| \$1input.json(x) | 此函数计算 JSONPath 表达式并以 JSON 字符串形式返回结果。 例如，`$input.json('$.pets')` 将返回一个表示宠物结构的 JSON 字符串。 有关 JSONPath 的更多信息，请参阅 [JSONPath](https://goessner.net/articles/JsonPath/) 或[适用于 Java 的 JSONPath](https://github.com/json-path/JsonPath)。 | 
| \$1input.path(x) | 获取一个 JSONPath 表达式字符串 (`x`) 并返回结果的 JSON 对象表达式。这样，您便可通过 [Apache Velocity 模板语言 (VTL)](https://velocity.apache.org/engine/devel/vtl-reference.html) 在本机访问和操作负载的元素。 例如，如果表达式 `$input.path('$.pets')` 返回一个如下所示的对象： <pre>[<br />  { <br />    "id": 1, <br />    "type": "dog", <br />    "price": 249.99 <br />  }, <br />  { <br />    "id": 2, <br />    "type": "cat", <br />    "price": 124.99 <br />  }, <br />  { <br />    "id": 3, <br />    "type": "fish", <br />    "price": 0.99 <br />  } <br />]</pre> `$input.path('$.pets').count()` 将返回 `"3"`。 有关 JSONPath 的更多信息，请参阅 [JSONPath](http://goessner.net/articles/JsonPath/) 或[适用于 Java 的 JSONPath](https://github.com/jayway/JsonPath)。 | 
| \$1stageVariables.<variable\$1name> |  *<variable\$1name>* 表示阶段变量名称。  | 
| \$1stageVariables['<variable\$1name>'] |  *<variable\$1name>* 表示任何阶段变量名称。  | 
| \$1\$1stageVariables['<variable\$1name>']\$1 |  *<variable\$1name>* 表示任何阶段变量名称。  | 
| \$1util.escapeJavaScript() |  使用 JavaScript 字符串规则对字符串中的字符进行转义。  此函数会将任何常规单引号 (`'`) 变成转义单引号 (`\'`)。但是，转义单引号在 JSON 中无效。因此，当此函数的输出用于 JSON 属性时，必须将任何转义单引号 (`\'`) 变回常规单引号 (`'`)。如下例所示:  <pre> $util.escapeJavaScript(data).replaceAll("\\'","'")</pre>   | 
| \$1util.parseJson() |   获取“字符串化的”JSON 并返回结果的对象表示形式。您可以使用此函数的结果通过 Apache Velocity 模板语言 (VTL) 在本机访问和操作负载的元素。例如，如果您具有以下负载： <pre>{"errorMessage":"{\"key1\":\"var1\",\"key2\":{\"arr\":[1,2,3]}}"}</pre>  并使用以下映射模板  <pre>#set ($errorMessageObj = $util.parseJson($input.path('$.errorMessage')))<br />{<br />   "errorMessageObjKey2ArrVal" : $errorMessageObj.key2.arr[0]<br />}<br /></pre> 您将得到以下输出： <pre>{<br />   "errorMessageObjKey2ArrVal" : 1<br />}<br /></pre>  | 
| \$1util.urlEncode() | 将字符串转换为“application/x-www-form-urlencoded”格式。 | 
| \$1util.urlDecode() | 对“application/x-www-form-urlencoded”字符串进行解码。 | 
| \$1util.base64Encode() | 将数据编码为 base64 编码的字符串。 | 
| \$1util.base64Decode() | 对 base64 编码字符串中的数据进行解码。 | 

# 针对 API Gateway 中的 WebSocket API 的二进制媒体类型
<a name="websocket-api-develop-binary-media-types"></a>

API Gateway WebSocket API 目前在传入消息负载中不支持二进制帧。如果客户端应用程序发送二进制帧，API Gateway 会拒绝它并断开客户端，而且显示代码 1003。

此行为有一种解决方法。如果客户端发送文本编码二进制数据（例如，Base64）作为文本帧，您可以将集成的 `contentHandlingStrategy` 属性设置为 `CONVERT_TO_BINARY`，以将负载从 Base64 编码的字符串转换为二进制。

要在非代理集成中返回二进制负载的路由响应，您可以将集成响应的 `contentHandlingStrategy` 属性设置为 `CONVERT_TO_TEXT`，以将负载从二进制转换为 Base64 编码字符串。

# 调用 WebSocket API
<a name="apigateway-how-to-call-websocket-api"></a>

部署 WebSocket API 后，客户端应用程序可以连接并向其发送消息，而且您的后端服务可以向连接的客户端应用程序发送消息：
+ 您可以使用 `wscat` 连接到 WebSocket API 并向其发送消息以模拟客户端行为。请参阅[使用 `wscat` 连接到 WebSocket API 并向其发送消息](apigateway-how-to-call-websocket-api-wscat.md)。
+ 您可以使用后端服务中的 @connections API 向连接的客户端发送回调消息、获取连接信息或断开客户端连接。请参阅[在后端服务中使用 `@connections` 命令](apigateway-how-to-call-websocket-api-connections.md)。
+ 客户端应用程序可以使用自己的 WebSocket 库来调用您的 WebSocket API。

# 使用 `wscat` 连接到 WebSocket API 并向其发送消息
<a name="apigateway-how-to-call-websocket-api-wscat"></a>

`[wscat](https://www.npmjs.com/package/wscat)` 实用程序是一个方便的工具，用于测试您已在 API Gateway 中创建和部署的 WebSocket API。您可以按如下方式安装和使用 `wscat`：

1. 从 [https://www.npmjs.com/package/wscat](https://www.npmjs.com/package/wscat) 中下载 `wscat`。

1. 通过运行以下命令安装 `wscat`：

   ```
   npm install -g wscat
   ```

1. 要连接到 API，请运行 `wscat` 命令，如以下示例所示。请注意，此示例假定 `Authorization` 设置是 `NONE`。

   ```
   wscat -c wss://aabbccddee.execute-api.us-east-1.amazonaws.com/test/
   ```

   您需要将 `aabbccddee` 替换为实际的 API ID，该 ID 显示在 API Gateway 控制台中或由 AWS CLI [https://docs.aws.amazon.com/cli/latest/reference/apigatewayv2/create-api.html](https://docs.aws.amazon.com/cli/latest/reference/apigatewayv2/create-api.html) 命令返回。

   此外，如果您的 API 位于 `us-east-1` 以外的区域，则需要替换正确的区域。

1. 要测试您的 API，请在连接时输入以下消息：

   ```
   {"{jsonpath-expression}":"{route-key}"}
   ```

   其中 *\$1jsonpath-expression\$1* 是一个 JSONPath 表达式，*\$1route-key\$1* 是 API 的路由键。例如：

   ```
   {"action":"action1"}
   {"message":"test response body"}
   ```

   有关 JSONPath 的更多信息，请参阅 [JSONPath](https://goessner.net/articles/JsonPath/) 或[适用于 Java 的 JSONPath](https://github.com/json-path/JsonPath)。

1. 要从 API 断开连接，请输入 `ctrl-C`。

# 在后端服务中使用 `@connections` 命令
<a name="apigateway-how-to-call-websocket-api-connections"></a>

您的后端服务可以使用以下 WebSocket 连接 HTTP 请求向连接的客户端发送回调消息、获取连接信息或断开客户端连接。

**重要**  
这些请求使用 [IAM 授权](apigateway-websocket-control-access-iam.md)，因此您必须使用[签名版本 4 (SigV4)](https://docs.aws.amazon.com/IAM/latest/UserGuide/create-signed-request.html) 对其进行签名。为此，您可以使用 API Gateway 管理 API。有关更多信息，请参阅 [ApiGatewayManagementApi](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/apigatewaymanagementapi.html)。

在以下命令中，您需要将 `{api-id}` 替换为实际的 API ID，该 ID 显示在 API Gateway 控制台中或由 AWS CLI [create-api](https://docs.aws.amazon.com/cli/latest/reference/apigatewayv2/create-api.html) 命令返回。在使用此命令之前，必须先建立连接。

要向客户端发送回调消息，请使用：

```
POST https://{api-id}.execute-api.us-east-1.amazonaws.com/{stage}/@connections/{connection_id}
```

您可以通过使用 `[Postman](https://www.postman.com/)` 或通过调用 `[awscurl](https://github.com/okigan/awscurl)` 来测试此请求，如以下示例所示：

```
awscurl --service execute-api -X POST -d "hello world" https://{prefix}.execute-api.us-east-1.amazonaws.com/{stage}/@connections/{connection_id}
```

您需要对命令进行 URL 编码，如以下示例所示：

```
awscurl --service execute-api -X POST -d "hello world" https://aabbccddee.execute-api.us-east-1.amazonaws.com/prod/%40connections/R0oXAdfD0kwCH6w%3D
```

要获取客户端的最新连接状态，请使用：

```
GET https://{api-id}.execute-api.us-east-1.amazonaws.com/{stage}/@connections/{connection_id}
```

要断开客户端连接，请使用：

```
DELETE https://{api-id}.execute-api.us-east-1.amazonaws.com/{stage}/@connections/{connection_id}
```

您可以通过在集成中使用 `$context` 变量来动态构建回调 URL。例如，如果您将 Lambda 代理集成与 `Node.js` Lambda 函数一起使用，则可以按如下方式构建 URL 并向连接的客户端发送消息：

```
import {
  ApiGatewayManagementApiClient,
  PostToConnectionCommand,
} from "@aws-sdk/client-apigatewaymanagementapi";

export const handler = async (event) => {
  const domain = event.requestContext.domainName;
  const stage = event.requestContext.stage;
  const connectionId = event.requestContext.connectionId;
  const callbackUrl = `https://${domain}/${stage}`;
  const client = new ApiGatewayManagementApiClient({ endpoint: callbackUrl });

  const requestParams = {
    ConnectionId: connectionId,
    Data: "Hello!",
  };

  const command = new PostToConnectionCommand(requestParams);

  try {
    await client.send(command);
  } catch (error) {
    console.log(error);
  }

  return {
    statusCode: 200,
  };
};
```

如果您为 WebSocket API 使用自定义域名，请从函数代码中移除 `stage` 变量。

发送回调消息时，您的 Lambda 函数必须有权调用 API Gateway 管理 API。如果您在连接建立之前或客户端断开连接后发布消息，则可能会收到一条包含 `GoneException` 的错误。

# 发布 WebSocket API 供客户调用
<a name="websocket-api-publish"></a>

仅仅创建和开发 API Gateway API 并不会自动使其可供用户调用。要使 API 可供调用，您必须将其部署到一个阶段。此外，建议您自定义用户将用于访问 API 的 URL。您可以为其提供一个与品牌一致的域，或者使其比 API 的默认 URL 更容易记住。

在本节中，您可以了解如何部署 API 并自定义您提供给用户以访问 API 的 URL。

**注意**  
为了增强您的 API Gateway API 的安全性，将在[公共后缀列表 (PSL)](https://publicsuffix.org/) 中注册 `execute-api.{region}.amazonaws.com` 域。为进一步增强安全性，如果您需要在 API Gateway API 的默认域名中设置敏感 Cookie，我们建议您使用带 `__Host-` 前缀的 Cookie。这将有助于保护您的域，防范跨站点请求伪造 (CSRF) 攻击。要了解更多信息，请参阅 Mozilla 开发者网络中的 [Set-Cookie](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#cookie_prefixes) 页面。

**Topics**
+ [为 API Gateway 中的 WebSocket API 创建阶段](websocket-api-stages.md)
+ [在 API Gateway 中部署 WebSocket API](apigateway-set-up-websocket-deployment.md)
+ [针对 API Gateway 中的 WebSocket API 的安全策略](websocket-api-ciphers.md)
+ [针对 API Gateway 中的 WebSocket API 自定义域名](websocket-api-custom-domain-names.md)

# 为 API Gateway 中的 WebSocket API 创建阶段
<a name="websocket-api-stages"></a>

一个 API 阶段是对您 API 生命周期状态（例如，`dev`、`prod`、`beta` 或 `v2`）的一次逻辑引用。API 阶段通过 API ID 和阶段名称标识，包含在您用于调用 API 的 URL 中。每个阶段都是一个对 API 部署的命名引用，可供客户端应用程序调用。

部署是 API 配置的快照。将 API 部署到阶段后，客户端可以调用该 API。您必须部署 API 才能使更改生效。

## 阶段变量
<a name="websocket-api-stages.stage-variables"></a>

阶段变量是您可以为 WebSocket API 的阶段定义的键/值对。它们与环境变量的功能类似，可用于 API 设置。

例如，您可以定义阶段变量，然后将其值设置为某个 HTTP 代理集成的 HTTP 端点。稍后，您可以使用关联的阶段变量名称引用端点。通过执行此操作，您可以在各个阶段对不同端点使用相同的 API 设置。同样，您可以使用阶段变量，为 API 的各个阶段指定不同的 AWS Lambda 函数集成。

**注意**  
阶段变量不适用于敏感数据，例如凭证。要将敏感数据传递给集成，请使用 AWS Lambda 授权方。您可以在 Lambda 授权方的输出中将敏感数据传递给集成。要了解更多信息，请参阅“[Lambda 授权方响应格式](http-api-lambda-authorizer.md#http-api-lambda-authorizer.payload-format-response)”。

### 示例
<a name="websocket-api-stages.stage-variables-examples"></a>

要使用阶段变量自定义 HTTP 集成端点，您必须首先设置阶段变量的名称和值（例如 `url`，值为 `example.com`）。接下来，设置 HTTP 代理集成。您可以告知 API Gateway 使用阶段变量值 **http://\$1\$1stageVariables.url\$1**，而不是输入端点的 URL。此值将指示 API Gateway 在运行时替换您的阶段变量 `${}`，具体取决于 API 所处的阶段。

您可以通过类似的方式引用阶段变量，用于指定 Lambda 函数名称或AWS角色 ARN。

将 Lambda 函数名称指定为阶段变量值时，您必须手动配置对 Lambda 函数的权限。以下 [add-permission](https://docs.aws.amazon.com/cli/latest/reference/lambda/add-permission.html) 命令添加所需的权限：

```
aws lambda add-permission --function-name arn:aws:lambda:XXXXXX:your-lambda-function-name --source-arn arn:aws:execute-api:us-east-1:YOUR_ACCOUNT_ID:api_id/*/HTTP_METHOD/resource --principal apigateway.amazonaws.com --statement-id apigateway-access --action lambda:InvokeFunction
```

## API Gateway 阶段变量参考
<a name="websocket-api-stages.stage-variables-reference"></a>

### HTTP 集成 URI
<a name="websocket-api-stages.stage-variables-in-integration-HTTP-uris"></a>

您可将阶段变量用作 HTTP 集成 URI 的一部分，如以下示例所示。
+ 不带协议的完整 URI – `http://${stageVariables.<variable_name>}`
+ 完整域 – `http://${stageVariables.<variable_name>}/resource/operation`
+ 子域 – `http://${stageVariables.<variable_name>}.example.com/resource/operation`
+ 路径 – `http://example.com/${stageVariables.<variable_name>}/bar`
+ 查询字符串 – `http://example.com/foo?q=${stageVariables.<variable_name>}` 

### Lambda 函数
<a name="websocket-api-stages.stage-variables-in-integration-lambda-functions"></a>

 您可以使用阶段变量代替 Lambda 函数名称或别名，如以下示例所示。
+ `arn:aws:apigateway:<region>:lambda:path/2015-03-31/functions/arn:aws:lambda:<region>:<account_id>:function:${stageVariables.<function_variable_name>}/invocations`
+ `arn:aws:apigateway:<region>:lambda:path/2015-03-31/functions/arn:aws:lambda:<region>:<account_id>:function:<function_name>:${stageVariables.<version_variable_name>}/invocations`

**注意**  
要将阶段变量用于 Lambda 函数，该函数必须与 API 位于同一账户中。阶段变量不支持跨账户 Lambda 函数。

### AWS 集成凭证
<a name="websocket-api-stages.stage-variables-in-integration-aws-credentials"></a>

 您可以在 AWS 用户或角色凭证 ARN 中使用阶段变量，如以下示例所示。
+  `arn:aws:iam::<account_id>:${stageVariables.<variable_name>}` 

# 在 API Gateway 中部署 WebSocket API
<a name="apigateway-set-up-websocket-deployment"></a>

 在创建 WebSocket API 之后，您必须对其进行部署，以便您的用户可以调用它。

要部署 API，您可以创建 [API 部署](api-gateway-basic-concept.md#apigateway-definition-api-deployment)并将其与[阶段](api-gateway-basic-concept.md#apigateway-definition-api-stage)关联。每个阶段都是 API 的一个快照，可供客户端应用程序调用。

**重要**  
每次更新 API 后，都必须重新部署 API。对阶段设置以外的任何内容进行更改都需要重新部署，包括修改以下资源：  
路线
集成
授权方
默认情况下，您将受到每个 API 10 个阶段的限制。我们建议您为部署重用阶段。

为调用已部署的 WebSocket API，客户端会向 API 的 URL 发送消息。URL 由 API 的主机名和阶段名称确定。

**注意**  
API Gateway 将支持最大 128 KB 的负载，最大帧大小为 32 KB。如果消息超过 32 KB，则必须将其拆分为多个帧，每个 32 KB 或更小。

使用 API 的默认域名，给定阶段 (`{stageName}`) 中的 WebSocket API 的 URL（例如）采用以下格式：

```
wss://{api-id}.execute-api.{region}.amazonaws.com/{stageName}
```

要使 WebSocket API 的 URL 对用户更友好，您可以创建自定义域名（如 `api.example.com`）来替换该 API 的默认主机名。配置过程与 REST API 相同。有关更多信息，请参阅 [API Gateway 中公共 REST API 的自定义域名](how-to-custom-domains.md)。

阶段实现了对 API 的可靠版本控制。例如，您可以将 API 部署到 `test` 阶段和 `prod` 阶段，并使用 `test` 阶段作为测试版本，使用 `prod` 阶段作为稳定版本。更新通过测试之后，您可以将 `test` 阶段提升到 `prod` 阶段。可以通过将 API 重新部署到 `prod` 阶段来完成升级。有关阶段的详细信息，请参阅[为 API Gateway 中的 REST API 设置阶段](set-up-stages.md)。

**Topics**
+ [使用 AWS CLI 创建 WebSocket API 部署](#apigateway-create-websocket-deployment-using-awscli)
+ [使用 API Gateway 控制台创建 WebSocket API 部署](#apigateway-create-websocket-deployment-using-console)

## 使用 AWS CLI 创建 WebSocket API 部署
<a name="apigateway-create-websocket-deployment-using-awscli"></a>

下面的 [create-deployment](https://docs.aws.amazon.com/cli/latest/reference/apigatewayv2/create-deployment.html) 命令将创建一个部署。

```
aws apigatewayv2 --region us-east-1 create-deployment --api-id aabbccddee
```

输出将与以下内容类似：

```
{
    "DeploymentId": "fedcba",
    "DeploymentStatus": "DEPLOYED",
    "CreatedDate": "2018-11-15T06:49:09Z"
}
```

在您将此部署与阶段关联之前，部署的 API 不可调用。您可以创建新阶段或重用之前创建的阶段。

使用以下 [create-stage](https://docs.aws.amazon.com/cli/latest/reference/apigatewayv2/create-stage.html) 命令创建新的阶段并将其与部署关联：

```
aws apigatewayv2 --region us-east-1 create-stage --api-id aabbccddee --deployment-id fedcba --stage-name test
```

输出内容如下所示：

```
{
    "StageName": "test",
    "CreatedDate": "2018-11-15T06:50:28Z",
    "DeploymentId": "fedcba",
    "DefaultRouteSettings": {
        "MetricsEnabled": false,
        "ThrottlingBurstLimit": 5000,
        "DataTraceEnabled": false,
        "ThrottlingRateLimit": 10000.0
    },
    "LastUpdatedDate": "2018-11-15T06:50:28Z",
    "StageVariables": {},
    "RouteSettings": {}
}
```

您还可以使用新创建的部署 ID（*deployment-id*）来更新阶段的 `deploymentId` 属性，以便重复使用现有的阶段。使用以下 [update-stage](https://docs.aws.amazon.com/cli/latest/reference/apigatewayv2/update-stage.html) 命令更新阶段的部署 ID：

```
aws apigatewayv2 update-stage --region region \
    --api-id api-id \ 
    --stage-name stage-name \ 
    --deployment-id deployment-id
```

## 使用 API Gateway 控制台创建 WebSocket API 部署
<a name="apigateway-create-websocket-deployment-using-console"></a>

要使用 API Gateway 控制台为 WebSocket API 创建部署，请执行以下操作：

1. 登录 API Gateway 控制台并选择 API。

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

1. 从下拉列表中选择所需的阶段，或输入新阶段的名称。

# 针对 API Gateway 中的 WebSocket API 的安全策略
<a name="websocket-api-ciphers"></a>

API Gateway 对所有 WebSocket API 端点强制执行 `TLS_1_2` 的安全策略。

*安全策略* 是 Amazon API Gateway 提供的最低 TLS 版本和密码套件的预定义组合。TLS 协议解决了网络安全问题，例如客户端和服务器之间的篡改和窃听。当您的客户端通过自定义域建立与您 API 的 TLS 握手时，安全策略实施客户端可以选择使用的 TLS 版本和密码套件选项。此安全策略接受 TLS 1.2 和 TLS 1.3 流量并拒绝 TLS 1.0 流量。

## WebSocket API 支持的 TLS 协议和密码
<a name="websocket-api-custom-domain-ciphers-list"></a>

下表描述了 WebSocket API 支持的 TLS 协议。


| **TLS 协议** | **TLS\$11\$10 安全策略** | 
| --- | --- | 
| TLSv1.3 | ![\[alt text not found\]](http://docs.aws.amazon.com/zh_cn/apigateway/latest/developerguide/images/success_icon.svg) 是 | 
| TLSv1.2 | ![\[alt text not found\]](http://docs.aws.amazon.com/zh_cn/apigateway/latest/developerguide/images/success_icon.svg) 是 | 

下表描述了适用于 WebSocket API 的 TLS 1\$12 安全策略的 TLS 密码。


| **TLS 密码** | **TLS\$11\$10 安全策略** | 
| --- | --- | 
| TLS\$1AES\$1128\$1GCM\$1SHA256 | ![\[alt text not found\]](http://docs.aws.amazon.com/zh_cn/apigateway/latest/developerguide/images/success_icon.svg) 是 | 
| TLS\$1AES\$1256\$1GCM\$1SHA384 | ![\[alt text not found\]](http://docs.aws.amazon.com/zh_cn/apigateway/latest/developerguide/images/success_icon.svg) 是 | 
| TLS\$1CHACHA20\$1POLY1305\$1SHA256 | ![\[alt text not found\]](http://docs.aws.amazon.com/zh_cn/apigateway/latest/developerguide/images/success_icon.svg) 是 | 
| ECDHE-ECDSA-AES128- GCM-SHA256 | ![\[alt text not found\]](http://docs.aws.amazon.com/zh_cn/apigateway/latest/developerguide/images/success_icon.svg) 是 | 
| ECDHE-RSA-AES128- GCM-SHA256 | ![\[alt text not found\]](http://docs.aws.amazon.com/zh_cn/apigateway/latest/developerguide/images/success_icon.svg) 是 | 
| ECDHE-ECDSA-AES128-SHA256 | ![\[alt text not found\]](http://docs.aws.amazon.com/zh_cn/apigateway/latest/developerguide/images/success_icon.svg) 是 | 
| ECDHE-RSA-AES128-SHA256 | ![\[alt text not found\]](http://docs.aws.amazon.com/zh_cn/apigateway/latest/developerguide/images/success_icon.svg) 是 | 
| ECDHE-ECDSA-AES256- GCM-SHA384 | ![\[alt text not found\]](http://docs.aws.amazon.com/zh_cn/apigateway/latest/developerguide/images/success_icon.svg) 是 | 
| ECDHE-RSA-AES256- GCM-SHA384 | ![\[alt text not found\]](http://docs.aws.amazon.com/zh_cn/apigateway/latest/developerguide/images/success_icon.svg) 是 | 
| ECDHE-ECDSA-AES256-SHA384 | ![\[alt text not found\]](http://docs.aws.amazon.com/zh_cn/apigateway/latest/developerguide/images/success_icon.svg) 是 | 
| ECDHE-RSA-AES256-SHA384 | ![\[alt text not found\]](http://docs.aws.amazon.com/zh_cn/apigateway/latest/developerguide/images/success_icon.svg) 是 | 
| AES128-GCM-SHA256 | ![\[alt text not found\]](http://docs.aws.amazon.com/zh_cn/apigateway/latest/developerguide/images/success_icon.svg) 是 | 
| AES128-SHA256 | ![\[alt text not found\]](http://docs.aws.amazon.com/zh_cn/apigateway/latest/developerguide/images/success_icon.svg) 是 | 
| AES256-GCM-SHA384 | ![\[alt text not found\]](http://docs.aws.amazon.com/zh_cn/apigateway/latest/developerguide/images/success_icon.svg) 是 | 
| AES256-SHA256 | ![\[alt text not found\]](http://docs.aws.amazon.com/zh_cn/apigateway/latest/developerguide/images/success_icon.svg) 是 | 

## OpenSSL 和 RFC 密码名称
<a name="apigateway-secure-connections-openssl-rfc-cipher-names-websocket"></a>

OpenSSL 和 IETF RFC 5246 为相同的密码使用不同的名称。有关密码名称的列表，请参阅[OpenSSL 和 RFC 密码名称](apigateway-security-policies-list.md#apigateway-secure-connections-openssl-rfc-cipher-names)。

## 有关 REST API 和 HTTP API 的信息
<a name="apigateway-websocket-additional-apis"></a>

有关 REST API 和 HTTP API 的更多信息，请参阅[选择针对 API Gateway 中自定义域的安全策略](apigateway-custom-domain-tls-version.md)和[API Gateway 中的 HTTP API 的安全策略](http-api-ciphers.md)。

# 针对 API Gateway 中的 WebSocket API 自定义域名
<a name="websocket-api-custom-domain-names"></a>

*自定义域名* 是您可以提供给 API 用户的更简单、更直观的 URL。

部署 API 后，您（和您的客户）可以使用以下格式的默认基本 URL 调用 API：

```
https://api-id.execute-api.region.amazonaws.com/stage
```

其中 *api-id* 由 API Gateway 生成，*region* 是 AWS 区域，*stage* 由您在部署 API 时指定。

URL 的主机名部分（即 `api-id.execute-api.region.amazonaws.com`）是指 API 端点。默认 API 端点名称是随机生成的，难以重新调用，对用户不友好。

使用自定义域名，您可以设置 API 的主机名，并选择基本路径（例如 `myservice`）以将备用 URL 映射到 API。例如，一个更为用户友好的 API 基本 URL 可以变成：

```
https://api.example.com/myservice
```

## 注意事项
<a name="websocket-api-custom-domain-names-considerations"></a>

以下注意事项可能会影响您对自定义域名的使用。
+ 如果将一个自定义域名映射到了 WebSocket API，就无法将其映射到 REST API 或 HTTP API。
+ 仅支持区域自定义域名。
+ 对于最低 TLS 版本，仅支持 TLS 1.2。
+ 您必须创建或更新 DNS 提供程序的资源记录以映射到您的 API 端点。如果没有此类映射，针对自定义域名的 API 请求无法到达 API Gateway。
+ 您可以使用通配符证书，在不超过默认配额的情况下支持几乎无限数量的域名。有关更多信息，请参阅 [通配符自定义域名](http-api-custom-domain-names.md#http-wildcard-custom-domain-names)。

## 先决条件
<a name="websocket-api-custom-domain-names-prerequisites"></a>

以下是自定义域名的先决条件。

### 注册域名
<a name="websocket-api-custom-domain-names-register"></a>

您必须拥有已注册的 Internet 域名，以便为 API 设置自定义域名。您可以使用 [Amazon Route 53](https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/) 或使用您选择的第三方域注册商注册互联网域名。自定义域名可以是注册的互联网域的子域或根域（也称为“机构根网域”）名称。

域名必须遵循 [RFC 1035](https://tools.ietf.org/html/rfc1035#section-2.3.4) 规范，每个标签最多可以有 63 个八位字节，总共可以有 255 个八位字节。

### 自定义域名的证书
<a name="websocket-api-custom-domain-names-certificates"></a>

为 API 设置自定义域名之前，您必须先在 ACM 中准备好 SSL/TLS 证书。如果 ACM 在您要创建自定义域名的 AWS 区域中不可用，您必须将证书导入到该区域的 API Gateway。

要导入 SSL/TLS 证书，您必须针对自定义域名提供 PEM 格式的 SSL/TLS 证书文本、其私有密钥和证书链。

存储在 ACM 中的每个证书均由其 ARN 标识。如果拥有 ACM 颁发的证书，那么您就无需担心公开任何敏感的证书详细信息，如私有密钥。要针对域名使用 AWS 托管的证书，您只需参考其 ARN 即可。

如果您的应用程序使用证书固定（有时称为 SSL 固定）来固定 ACM 证书，则在 AWS 续订证书后，应用程序可能无法连接到您的域。有关更多信息，请参阅《AWS Certificate Manager 用户指南》**中的[证书固定问题](https://docs.aws.amazon.com/acm/latest/userguide/troubleshooting-pinning.html)。

## 通配符自定义域名
<a name="websocket-api-wildcard-custom-domain-names"></a>

使用通配符自定义域名，您可以在不超过[默认配额](limits.md)的情况下支持几乎无限数量的域名。例如，您可以为每位客户提供自己的域名 `customername.api.example.com`。

要创建通配符自定义域名，可以指定通配符 (`*`) 作为表示根域所有可能子域的自定义域的第一个子域。

例如，通配符自定义域名 `*.example.com` 会生成子域，如 `a.example.com`、`b.example.com` 和 `c.example.com`，这些子域都会路由到同一个域。

通配符自定义域名支持与 API Gateway 的标准自定义域名不同的配置。例如，在单个 AWS 账户中，您可以对 `*.example.com` 和 `a.example.com` 进行不同的配置。

您可以使用 `$context.domainName` 和 `$context.domainPrefix` 上下文变量来确定客户端用于调用 API 的域名。要了解有关上下文变量的更多信息，请参阅 [API Gateway 的用于数据转换的变量](api-gateway-mapping-template-reference.md)。

要创建通配符自定义域名，您必须提供已使用 DNS 或电子邮件验证方法验证的由 ACM 颁发的证书。

**注意**  
如果其他 AWS 账户已经创建了与通配符自定义域名冲突的自定义域名，则无法创建通配符自定义域名。例如，如果账户 A 已经创建了 `a.example.com`，则账户 B 无法创建通配符自定义域名 `*.example.com`。  
如果账户 A 和账户 B 共享拥有者，您可以联系 [AWS Support 中心](https://console.aws.amazon.com/support/home#/)请求例外。

## 自定义域名的后续步骤
<a name="websocket-api-custom-domain-names-next-steps"></a>

要为 HTTP API 设置自定义域名，您可以使用《API Gateway 开发人员指南》中的“REST API”部分的文档。

首先，为自定义域名指定一个证书。有关更多信息，请参阅 [在 AWS Certificate Manager 中准备好证书](how-to-specify-certificate-for-custom-domain-name.md)。然后，创建一个区域性自定义域名。有关更多信息，请参阅 [在 API Gateway 中设置区域自定义域名](apigateway-regional-api-custom-domain-create.md)。

# 将 API 阶段映射到 WebSocket API 的自定义域名
<a name="websocket-api-mappings"></a>

您可以使用 API 映射将 API 阶段连接到自定义域名。创建域名并配置 DNS 记录后，您可以使用 API 映射通过自定义域名向 API 发送流量。

API 映射指定了用于映射的 API、阶段以及可选的路径。例如，您可以将 API 的 `production` 阶段映射到 `wss://api.example.com/orders`。

在创建 API 映射之前，您必须拥有 API、阶段和自定义域名。要了解有关创建自定义域名的更多信息，请参阅 [在 API Gateway 中设置区域自定义域名](apigateway-regional-api-custom-domain-create.md)。

## 限制
<a name="websocket-api-mappings-restrictions"></a>
+ 在 API 映射中，自定义域名和映射的 API 必须位于同一个AWS账户中。
+ API 映射必须仅包含字母、数字和以下字符：`$-_.+!*'()`。
+ API 映射中路径的最大长度为 300 个字符。
+ 您不能将 WebSocket API 映射到与 HTTP API 或 REST API 相同的自定义域名。
+ 如果您创建具有多个级别的 API 映射，API Gateway 会将所有标头名称转换为小写。

## 创建 API 映射
<a name="websocket-api-mappings-examples"></a>

要创建 API 映射，您必须首先创建自定义域名、API 和阶段。有关使用自定义域名的更多信息，请参阅 [在 API Gateway 中设置区域自定义域名](apigateway-regional-api-custom-domain-create.md)。

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

**创建 API 映射**

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

1. 选择**自定义域名**。

1. 选择您已经创建的自定义域名。

1. 选择 **API 映射**。

1. 选择 **Configure API mappings (配置 API 映射)**。

1. 选择 **Add new mapping (添加新映射)**。

1. 输入 **API**、**阶段**以及可选的**路径**。

1. 选择**保存**。

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

使用以下 [create-api-mapping](https://docs.aws.amazon.com/cli/latest/reference/apigatewayv2/create-api-mapping.html) 命令创建 API 映射。在此示例中，API Gateway 将请求发送到 `api.example.com/v1`，到指定的 API 和阶段。

```
aws apigatewayv2 create-api-mapping \
    --domain-name api.example.com \
    --api-mapping-key v1 \
    --api-id a1b2c3d4 \
    --stage test
```

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

以下 CloudFormation 示例会创建一个 API 映射。

```
MyApiMapping:
  Type: 'AWS::ApiGatewayV2::ApiMapping'
  Properties:
    DomainName: api.example.com
    ApiMappingKey: 'v1'
    ApiId: !Ref MyApi
    Stage: !Ref MyStage
```

------

# WebSocket API 的自定义域名的 IP 地址类型
<a name="websocket-api-custom-domain-names-ip-address-type"></a>

当您创建自定义域名时，您指定可以调用域的 IP 地址的类型。可以选择 IPv4 以解析 IPv4 地址来调用域，也可以选择双堆栈以同时支持 IPv4 和 IPv6 地址调用域。我们建议您将 IP 地址类型设置为双堆栈，以缓解 IP 空间耗尽或保护您的安全状况。有关双堆栈 IP 地址类型的优势的更多信息，请参阅 [IPv6 on AWS](https://docs.aws.amazon.com/whitepapers/latest/ipv6-on-aws/internet-protocol-version-6.html)。

## IP 地址类型的注意事项
<a name="websocket-api-custom-domain-names-ip-address-type-considerations"></a>

以下注意事项可能会影响您对 IP 地址类型的使用。
+ API Gateway 自定义域名的默认 IP 地址类型是 IPv4。
+ 对于映射到自定义域名的所有 API，自定义域名不需要具有相同的 IP 地址类型。如果您禁用默认 API 端点，则这可能会影响调用方调用 API 的方式。

## 更改自定义域名的 IP 地址类型
<a name="websocket-api-custom-domain-names-ip-address-type-change"></a>

您可以通过更新域名的端点配置来更改 IP 地址类型。您可以使用 AWS 管理控制台、AWS CLI、CloudFormation 或 AWS SDK 更新端点配置。

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

**更改自定义域名的 IP 地址类型**

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

1. 选择公有自定义域名。

1. 选择**端点配置**。

1. 对于 IP 地址类型，选择 **IPv4** 或**双堆栈**。

1. 选择**保存**。

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

以下 [update-domain-name](https://docs.aws.amazon.com/cli/latest/reference/apigatewayv2/update-domain-name.html) 命令将 API 更新为具有双堆栈 IP 地址类型：

```
aws apigatewayv2 update-domain-name \
   --domain-name dualstack.example.com \
   --domain-name-configurations CertificateArn=arn:aws:acm:us-east-1:111122223333:certificate/abcd1234-5678-abc,IpAddressType=dualstack
```

输出将与以下内容类似：

```
{
    "ApiMappingSelectionExpression": "$request.basepath",
    "DomainName": "dualstack.example.com",
    "DomainNameConfigurations": [
        {
            "ApiGatewayDomainName": "d-abcd1234.execute-api.us-east-1.amazonaws.com",
            "CertificateArn": "arn:aws:acm:us-east-1:111122223333:certificate/abcd1234-5678-abc",
            "DomainNameStatus": "AVAILABLE",
            "EndpointType": "REGIONAL",
            "HostedZoneId": "Z3LQWSYCGH4ADY",
            "SecurityPolicy": "TLS_1_2",
            "IpAddressType": "dualstack"
        }
    ],
    "Tags": {}
}
```

------

# 禁用 WebSocket API 的默认端点
<a name="websocket-api-disable-default-endpoint"></a>

默认情况下，客户端可以通过使用 API Gateway 为 API 生成的 `execute-api` 端点来调用您的 API。为确保客户端只能通过使用自定义域名访问您的 API，请禁用默认 `execute-api` 端点。禁用默认端点时，它会影响 API 的所有阶段。

以下过程说明了如何禁用 WebSocket API 的默认端点。

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

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

1. 选择 WebSocket API。

1. 选择 **API 设置**。

1. 在 **API 详细信息**选项卡上，选择**编辑**。

1. 对于**默认端点**，选择**非活动**。

1. 选择 **Save changes（保存更改）**。

1. 在主导航窗格中，选择**路由**。

1. 选择**部署**，然后重新部署您的 API 或创建一个新阶段使更改生效。

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

以下 [update-api](https://docs.aws.amazon.com/cli/latest/reference/apigatewayv2/update-api.html) 命令会禁用 WebSocket API 的默认端点。

```
aws apigatewayv2 update-api \
    --api-id abcdef123 \
    --disable-execute-api-endpoint
```

禁用默认端点后，必须部署 API 才能使更改生效。

以下 AWS CLI 命令会创建部署。

```
aws apigatewayv2 create-deployment \
    --api-id abcdef123 \
    --stage-name dev
```

------

# 保护 API Gateway 中的 WebSocket API
<a name="websocket-api-protect"></a>

API Gateway 提供了多种方法来保护您的 API 免受某些威胁，例如恶意用户或流量高峰。您可以使用诸如生成 SSL 证书或设置节流目标等策略来保护 API。有关生成 SSL 证书的更多信息，请参阅[生成和配置 SSL 证书以用于 API Gateway 中的后端身份验证](getting-started-client-side-ssl-authentication.md)。本节的其余部分介绍设置节流目标。

您可以为 API 配置节流，以帮助防止它们因请求过多而不堪重负。节流是在尽最大努力的基础上应用的，应被视为目标而不是保证的请求上限。

API Gateway 使用令牌桶算法（其中，一个令牌即一个请求）限制对 API 的请求。具体来说，API Gateway 根据您账户中的所有 API，按区域检查请求提交的速率和突发事件。在令牌桶算法中，突发可以允许这些限制的预定义超出，但在某些情况下，其他因素也可能导致限制超支。

如果请求提交超过稳态请求速率和突增限制，则 API Gateway 将开始限制请求。此时客户可能会收到 `429 Too Many Requests` 个错误响应。捕获此类异常后，客户端能够以限制速率的方式重新提交失败的请求。

作为 API 开发人员，您可以针对各个 API 阶段或方法设置目标限制，以提高账户中所有 API 的整体性能。

## 每个区域的账户级别限制
<a name="websocket-api-protect-throttling-account"></a>

默认情况下，API Gateway 针对每个区域限制 AWS 账户内所有 API 的每秒稳态请求 (RPS)。它还对于每个区域限制一个 AWS 账户中所有 API 的突增（即最大存储桶大小）。在 API Gateway 中，突增限制代表 API Gateway 在返回 `429 Too Many Requests` 错误响应之前可以完成目标的最大并发请求提交数量。有关限制配额的更多信息，请参阅[Amazon API Gateway 配额](limits.md)。

每个账户限制适用于指定区域内账户中的所有 API。客户可以请求我们放宽账户级别的速率限制 —— 如果具有更短的超时和较小的有效负载的 API，则可以提高限制。要请求增加每个区域的账户级别限制，请联系 [AWS Support 中心](https://console.aws.amazon.com/support/home#/)。有关更多信息，请参阅 [Amazon API Gateway 配额](limits.md)。请注意，这些限制不能高于 AWS 节流限制。

## 路由级别限制
<a name="websocket-api-protect-throttling-route"></a>

您可以设置路由级别限制，用于覆盖 API 中特定阶段或各个路由的账户级别请求限制。原定设置的路由节流限制不能超过账户级别的费率限制。

您可以使用 AWS CLI 配置路由级限制。以下 [update-stage](https://docs.aws.amazon.com/cli/latest/reference/apigatewayv2/update-stage.html) 命令为 API 的指定阶段和路由配置自定义节流。

```
aws apigatewayv2 update-stage \
    --api-id a1b2c3d4 \
    --stage-name dev \
    --route-settings '{"messages":{"ThrottlingBurstLimit":100,"ThrottlingRateLimit":2000}}'
```

# 监控 API Gateway 中的 WebSocket API
<a name="websocket-api-monitor"></a>

您可以使用 CloudWatch 指标和 CloudWatch Logs 来监控 WebSocket API。通过合并日志和指标，您可以记录错误并监控 API 的性能。

**注意**  
在以下情况下，API Gateway 可能无法生成日志和指标：  
“413 请求实体过大”错误
过多的“429 请求太多”错误
发送到没有 API 映射的自定义域的请求中出现 400 系列错误
由内部故障造成的 500 系列错误

**Topics**
+ [使用 CloudWatch 指标监控 WebSocket API 执行](apigateway-websocket-api-logging.md)
+ [为 API Gateway 中的 WebSocket API 配置日志记录](websocket-api-logging.md)

# 使用 CloudWatch 指标监控 WebSocket API 执行
<a name="apigateway-websocket-api-logging"></a>

您可以使用 [Amazon CloudWatch](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/WhatIsCloudWatch.html) 指标来监控 WebSocket API。该配置类似于 REST API 使用的配置。有关更多信息，请参阅 [使用 Amazon CloudWatch 指标监控 REST API 执行](monitoring-cloudwatch.md)。

WebSocket API 支持以下指标：


| 指标 | 说明 | 
| --- | --- | 
| ConnectCount | 发送到 \$1connect 路由集成的消息数。 | 
| MessageCount | 从客户端发送到 WebSocket API 的消息数。 | 
| IntegrationError | 从集成返回 4XX/5XX 响应的请求数。 | 
| ClientError | 在调用集成之前由 API Gateway 返回 4XX 响应的请求数。 | 
| ExecutionError | 调用集成时发生的错误。 | 
| IntegrationLatency | API Gateway 向集成发送请求和 API Gateway 从集成接收响应之间的时间差。已对回调和模拟集成禁止。 | 

您可以使用下表中的维度筛选 API Gateway 指标。


| 维度 | 说明 | 
| --- | --- | 
| ApiId | 筛选具有指定 API ID 的 API 的 API Gateway 指标。 | 
| ApiId、阶段 | 针对具有指定 API ID 和阶段 ID 的 API 阶段筛选 API Gateway 指标。 | 
| ApiId、方法、资源、阶段 |  使用指定的 API ID、阶段 ID、资源路径和路由 ID 筛选 API 方法的 API Gateway 指标。 除非您明确启用了详细的 CloudWatch 指标，否则 API Gateway 不会发送这些指标。要执行此操作，您可以通过调用 API Gateway V2 REST API 的 [UpdateStage](https://docs.aws.amazon.com/apigatewayv2/latest/api-reference/apis-apiid-stages-stagename.html) 操作，将 `detailedMetricsEnabled` 属性更新为 `true`。或者，您也可以调用 [update-stage](https://docs.aws.amazon.com/cli/latest/reference/apigatewayv2/update-stage.html) AWS CLI 命令，以将 `DetailedMetricsEnabled` 属性更新为 `true`。启用这些指标会对您的账户额外计费。有关定价信息，请参阅 [Amazon CloudWatch 定价](https://aws.amazon.com/cloudwatch/pricing/)。  | 

# 为 API Gateway 中的 WebSocket API 配置日志记录
<a name="websocket-api-logging"></a>

您可以启用日志记录以将日志写入 CloudWatch Logs。在 CloudWatch 中有两种类型的 API 日志记录：执行日志记录和访问日志记录。在执行日志记录中，API Gateway 管理 CloudWatch Logs。该过程包括创建日志组和日志流，以及向日志流报告任意调用方的请求和响应。

为了改善您的安全状况，我们建议您使用 `ERROR` 或 `INFO` 级别的执行日志记录。为遵守各种合规性框架，您可能需要执行此操作。有关更多信息，请参阅《AWS Security Hub User Guide》**中的 [Amazon API Gateway Controls](https://docs.aws.amazon.com/securityhub/latest/userguide/apigateway-controls.html)。

在访问日志记录中，作为 API 开发人员，您想要记录谁访问了您的 API 以及调用方访问 API 的方式。您可以创建自己的日志组，或者选择可由 API Gateway 管理的现有日志组。要指定访问详细信息，您可以选择 `$context` 变量（以您选择的格式表示），并选择日志组作为目标。

有关如何设置 CloudWatch 日志记录的说明，请参阅[使用 API Gateway 控制台设置 CloudWatch API 日志记录](set-up-logging.md#set-up-access-logging-using-console)。

当您指定 **Log Format (日志格式)** 时，您可以选择要记录的上下文变量。支持以下变量。


| 参数 | 说明 | 
| --- | --- | 
| \$1context.apiId |  API Gateway 分配给您的 API 的标识符。  | 
| \$1context.authorize.error | 授权错误消息。 | 
| \$1context.authorize.latency | 授权延迟时间（以毫秒为单位）。 | 
| \$1context.authorize.status | 从授权尝试返回的状态代码。 | 
| \$1context.authorizer.error | 从授权方返回的错误消息。 | 
| \$1context.authorizer.integrationLatency | Lambda 授权方延迟（以毫秒为单位）。 | 
| \$1context.authorizer.integrationStatus | 从 Lambda 授权方返回的状态代码。 | 
| \$1context.authorizer.latency | 授权方延迟（以毫秒为单位）。 | 
| \$1context.authorizer.requestId | AWS 端点的请求 ID。 | 
| \$1context.authorizer.status | 从授权方返回的状态代码。 | 
| \$1context.authorizer.principalId |  与由客户端发送的令牌相关联的委托人用户标识，从API Gateway Lambda 授权方 Lambda 函数返回。（Lambda 授权方以前称为自定义授权方。）  | 
| \$1context.authorizer.property |  从 API Gateway Lambda 授权方函数返回的 `context` 映射的指定键/值对的字符串化值。例如，如果授权方返回以下 `context` 映射： <pre>"context" : {<br />                            "key": "value",<br />                            "numKey": 1,<br />                            "boolKey": true<br />                            }</pre> 调用 `$context.authorizer.key` 将返回 `"value"` 字符串，调用 `$context.authorizer.numKey` 将返回 `"1"` 字符串，而调用 `$context.authorizer.boolKey` 将返回 `"true"` 字符串。  | 
| \$1context.authenticate.error | 从身份验证尝试返回的错误消息。 | 
| \$1context.authenticate.latency | 身份验证延迟时间（以毫秒为单位）。 | 
| \$1context.authenticate.status | 从身份验证尝试返回的状态代码。 | 
| \$1context.connectedAt |  [Epoch](https://en.wikipedia.org/wiki/Unix_time) 格式的连接时间。  | 
| \$1context.connectionId |  连接的唯一 ID，可用于对客户端进行回调。  | 
| \$1context.domainName |  WebSocket API 的域名。这可用于对客户端进行回调（而不是硬编码值）。  | 
| \$1context.error.message |  包含 API Gateway 错误消息的字符串。  | 
| \$1context.error.messageString | \$1context.error.message 的带引号的值，即 "\$1context.error.message"。 | 
| \$1context.error.responseType |  错误响应类型。  | 
| \$1context.error.validationErrorString |  包含详细验证错误消息的字符串。  | 
| \$1context.eventType |  事件类型：`CONNECT`、`MESSAGE` 或 `DISCONNECT`。  | 
| \$1context.extendedRequestId | 等效于 \$1context.requestId。 | 
| \$1context.identity.accountId |  与请求关联的 AWS 账户 ID。  | 
| \$1context.identity.apiKey |  API 所有者密钥与启用密钥的 API 请求关联。  | 
| \$1context.identity.apiKeyId | API 密钥 ID 与启用密钥的 API 请求关联 | 
| \$1context.identity.caller |  签发请求的调用方的委托人标识符。对于使用 IAM 授权的路由支持此项。  | 
| \$1context.identity.cognitoAuthenticationProvider |  发出请求的调用方使用的所有 Amazon Cognito 身份验证提供商的逗号分隔列表。仅当使用 Amazon Cognito 凭证对请求签名时才可用。 例如，对于 Amazon Cognito 身份池中的身份，`cognito-idp. region.amazonaws.com/user_pool_id,cognito-idp.region.amazonaws.com/user_pool_id:CognitoSignIn:token subject claim` 有关更多信息，请参阅 *Amazon Cognito 开发人员指南* 中的[使用联合身份](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-identity.html)。 | 
| \$1context.identity.cognitoAuthenticationType |  发出请求的调用方的 Amazon Cognito 身份验证类型。仅当使用 Amazon Cognito 凭证对请求签名时才可用。可能的值包括经过身份验证的身份的 `authenticated` 和未经身份验证的身份的 `unauthenticated`。 | 
| \$1context.identity.cognitoIdentityId |  发出请求的调用方的 Amazon Cognito 身份 ID。仅当使用 Amazon Cognito 凭证对请求签名时才可用。  | 
| \$1context.identity.cognitoIdentityPoolId |  发出请求的调用方的 Amazon Cognito 身份池 ID。仅当使用 Amazon Cognito 凭证对请求签名时才可用。  | 
| \$1context.identity.principalOrgId |  [AWS 组织 ID](https://docs.aws.amazon.com/organizations/latest/userguide/orgs_manage_org_details.html)。对于使用 IAM 授权的路由支持此项。  | 
| \$1context.identity.sourceIp |  向 API Gateway 发出请求的 TCP 连接的源 IP 地址。  | 
| \$1context.identity.user |  将获得资源访问权限授权的用户的委托人标识符。对于使用 IAM 授权的路由支持此项。  | 
| \$1context.identity.userAgent |  API 调用方的用户代理。  | 
| \$1context.identity.userArn |  身份验证后标识的有效用户的 Amazon 资源名称 (ARN)。  | 
| \$1context.integration.error | 从集成返回的错误消息。 | 
| \$1context.integration.integrationStatus | 对于 Lambda 代理集成，从 AWS Lambda（而不是从后端 Lambda 函数代码）返回的状态代码。 | 
| \$1context.integration.latency | 集成延迟（毫秒）。等效于 \$1context.integrationLatency。 | 
| \$1context.integration.requestId | AWS 端点的请求 ID。等效于 \$1context.awsEndpointRequestId。 | 
| \$1context.integration.status | 从集成返回的状态代码。对于 Lambda 代理集成，这是 Lambda 函数代码返回的状态代码。等效于 \$1context.integrationStatus。 | 
| \$1context.integrationLatency | 集成延迟（毫秒），仅可用于访问日志记录。 | 
| \$1context.messageId |  消息的唯一服务器端 ID。仅当 `$context.eventType` 为 `MESSAGE` 时才可用。  | 
| \$1context.requestId |  与 `$context.extendedRequestId` 相同。  | 
| \$1context.requestTime | [CLF](https://httpd.apache.org/docs/current/logs.html#common) 格式的请求时间 (dd/MMM/yyyy:HH:mm:ss \$1-hhmm)。 | 
| \$1context.requestTimeEpoch | [Epoch](https://en.wikipedia.org/wiki/Unix_time) 格式的请求时间，以毫秒为单位。 | 
| \$1context.routeKey |  选定的路由键。  | 
| \$1context.stage |  API 调用的部署阶段（例如测试或生产）。  | 
| \$1context.status |  响应状态。  | 
| \$1context.waf.error | 从 返回的错误消息AWS WAF | 
| \$1context.waf.latency | AWS WAF 延迟时间（以毫秒为单位） | 
| \$1context.waf.status | 从 返回的状态代码AWS WAF | 

一些常用访问日志格式的示例在 API Gateway 控制台中显示，下面列出了这些格式。
+ `CLF` ([常用日志格式](https://httpd.apache.org/docs/current/logs.html#common) )：

  ```
  $context.identity.sourceIp $context.identity.caller \
  $context.identity.user [$context.requestTime] "$context.eventType $context.routeKey $context.connectionId" \
  $context.status $context.requestId
  ```

  继续符 (`\`) 用作视觉辅助。日志格式必须为单行。您可以在日志格式末尾添加换行符 (`\n`)，以便在每个日志条目末尾添加换行符。
+  `JSON`: 

  ```
  {
  "requestId":"$context.requestId", \
  "ip": "$context.identity.sourceIp", \
  "caller":"$context.identity.caller", \
  "user":"$context.identity.user", \
  "requestTime":"$context.requestTime", \
  "eventType":"$context.eventType", \
  "routeKey":"$context.routeKey", \
  "status":"$context.status", \
  "connectionId":"$context.connectionId"
  }
  ```

  继续符 (`\`) 用作视觉辅助。日志格式必须为单行。您可以在日志格式末尾添加换行符 (`\n`)，以便在每个日志条目末尾添加换行符。
+ `XML`: 

  ```
  <request id="$context.requestId"> \
   <ip>$context.identity.sourceIp</ip> \
   <caller>$context.identity.caller</caller> \
   <user>$context.identity.user</user> \
   <requestTime>$context.requestTime</requestTime> \
   <eventType>$context.eventType</eventType> \
   <routeKey>$context.routeKey</routeKey> \
   <status>$context.status</status> \
   <connectionId>$context.connectionId</connectionId> \
  </request>
  ```

  继续符 (`\`) 用作视觉辅助。日志格式必须为单行。您可以在日志格式末尾添加换行符 (`\n`)，以便在每个日志条目末尾添加换行符。
+ `CSV` (逗号分隔值)：

  ```
  $context.identity.sourceIp,$context.identity.caller, \
  $context.identity.user,$context.requestTime,$context.eventType, \
  $context.routeKey,$context.connectionId,$context.status, \
  $context.requestId
  ```

  继续符 (`\`) 用作视觉辅助。日志格式必须为单行。您可以在日志格式末尾添加换行符 (`\n`)，以便在每个日志条目末尾添加换行符。