

# 在 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` 的错误。