AWS API Gateway Websockets -- connectionID 在哪里?

AWS API Gateway Websockets -- where is the connectionID?

我正在 $connect 路由上使用自定义授权方设置 AWS API 网关 Websockets,如下所述:

https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-websocket-api-route-keys-connect-disconnect.html

我的问题是——如何获取 connectionID,即以后可用于向连接的客户端广播的标识符?

您可以从上下文变量中获取 connectionId。请参阅此处了解 WebSocket API 的可用变量: https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-websocket-api-mapping-template-reference.html

在 Lambda 函数中,您可以通过 event.requestContext 访问上下文变量。

这里的问题是在使用 HTTP 作为集成类型时——即在调用一个或多个 API GW 路由时命中 http 端点($connect/$disconnect/$invoke)。我们发现我们无法代理请求(这意味着我们丢失了原始 headers,包括 auth),但是如果我们需要连接 ID,我们必须指定一个请求模板并使用类似:

{"connectionId": "$context.connectionId", "body": "$input.body"}

问题没有具体说明使用什么类型的后端。 AWS API 网关的 AWS 文档适用于 lambda 函数 - 我找不到任何帮助将 connectionId 获取到我的 http 后端。

尝试 Big Endian 的回答,我发现了一些问题 - 我的 cakephp 后端无法解码引用的 json body。我找到了解决方案,但实现他的答案还需要许多其他步骤,因此它们是:

我在关闭 HTTP 代理的情况下创建了一个路由键,并按如下方式设置了一个请求模板(也是非常稀疏的文档):

  • 路由选择表达式:$request.body.action
  • 路由键:订阅
    这意味着所有带有 {"action": "subscribe"} 的请求都将通过这里

  • 集成请求类型:HTTP

  • HTTP 代理集成:关闭 - header 或通过
  • 进行身份验证
  • HTTP 方法:POST

然后是困难的部分:设置请求模板。我希望所有 "subscribe" 请求都使用此模板,我发现这样做的唯一方法是将模板选择表达式设置为与路由选择表达式相同:$request.body.action,并将模板键设置为"subscribe".

它最终成为对 API 应用此模板必须执行的相同内容的双重测试 - 如果任何 body 有更好的方法,请发表评论。

然后最后一步是输入此作为 'subscribe' 的 "Generate template":

{"connectionId": "$context.connectionId", "body": $input.body}

请注意,在我的例子中,我的 body 是 json 并且 $input.body 不在引号中 - body json 扩展为模板。我想如果 body 只是一个字符串,那么模板将是

{"connectionId": "$context.connectionId", "body": "$input.body"}

但是路由永远不会到达这里,因为路由需要 body 来包含 json 中的操作键。

非常感谢 Francois Stark,非常有帮助。

通过我自己的试验,我发现您可以使用 $default 路由和以下格式避免匹配 $request.body.action 的特定值:

  • 模板选择表达式:\$default <- 斜线很重要
  • 模板键:\$default <- 又是斜杠
  • 生成模板
{"connectionId": "$context.connectionId", "body": $input.body}

使用此配置,您的 HTTP 端点应该使用单个路由获取 'action' 所有值中的连接 ID 作为正文数据。

另外,在$connect$disconnect路由中获取connectionID,Request Template的格式是一样的,但是由于这些事件中没有body数据,可以省略正文:

  • 模板选择表达式:\$default <- 斜线很重要
  • 模板键:\$default <- 又是斜杠
  • 生成模板
{"connectionId": "$context.connectionId"}

使用此配置,您的 HTTP 端点应该在 $connect 和 $disconnect 事件中获取 connectionID 作为正文数据。

要向集成请求添加内容,您需要使用请求模板。

  1. 关闭路由的 HTTP 代理集成。 (否则您无法修改请求。)
  2. 保存您的更改。 (在您这样做之前,请求模板部分不会出现。)
  3. 设置您的模板选择表达式。这用于从传入的请求对象中查找值。 (如果要匹配所有传入请求,请输入 $default。注意斜杠。完整文档 here。)
  4. 设置您的模板密钥。这将与模板选择表达式选择的值进行比较。如果匹配,则使用模板。 (如果要匹配所有传入请求,请输入 $default。请注意没有斜杠。)
  5. 单击您的模板密钥以打开模板编辑器。这是您输入模板的地方,该模板将作为请求的主体发送到您的集成端点。例如,如果要将连接 ID 和传入查询参数转发到集成端点,可以使用以下内容:
{
    "myConnectionIdProperty": "$context.connectionId",
    "myQueryParams": $input.params()
}

可以找到模板表达式中可用变量的文档 here

(请注意,虽然 $request 是模板 Selection 表达式中的有效变量,但它不是模板本身的有效变量。使用 $input 而不是那里。)

您可以从 event.requestContext 获取 connectionId。

exports.handler = async (event) => {
const data = event['body'];
const connectionId = event['requestContext']['connectionId'];};

感谢大家尝试记录 AWS API 网关。

要能够使用 VPC Link 将数据从 AWS Websocket API 网关发送到您的集成服务,请执行以下操作:

  1. 取消选中使用代理集成

  2. 保存

  3. 设置请求模板如下图:

  4. 这将允许在请求正文中获取 connectionId、查询、正文。

  5. 保存

  6. 点击右上角的添加集成响应

  7. 设置积分响应如下图:

8。希望它能奏效。如果没有,请通过测试找出答案,然后在这里为其他人提供答案。谢谢。

I would suggest forget any other type of integration and just use lambda. Because the next problem you will face is getting query parameters that were passed at the time of connection in integration of disconnect.

要解决此问题,请转到您的 AWS 控制台 -> 打开您的 AWS CloudShell(在您的仪表板右上角)

对于使用HTTP_PROXY的WebSocket服务器,需要修改@connect路由添加connectionId

1- 在shell中输入:

# List all integrations

aws apigatewayv2 get-integrations --api-id xxxxxxxxx

# Update all @connect integration

aws apigatewayv2 update-integration --integration-id zzzzzzzz --api-id xxxxxxxxx --request-parameters 'integration.request.header.connectionId'='context.connectionId'

2- 之后不要忘记部署,否则将无法工作

为什么 AWS 不为您提供 connectionId?因为他们希望你使用 Lambda。