

# 针对 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 编码字符串中的数据进行解码。 | 