AWS API Gateway Websockets——connectionID 在哪里?

Posted

技术标签:

【中文标题】AWS API Gateway Websockets——connectionID 在哪里?【英文标题】:AWS API Gateway Websockets -- where is the connectionID? 【发布时间】:2019-06-05 15:11:32 【问题描述】:

我正在 $connect 路由上设置一个带有自定义授权方的 AWS API Gateway Websockets,如下所述:

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

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

【问题讨论】:

如何使用 HTTP ass 集成类型在 $connect 中获取 connectionID?我尝试了给定的答案,但出现错误。您能帮忙解决这个问题吗?? @RishabhGarg 试试"integration.request.header.connectionId": "$context.connectionId" 【参考方案1】:

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

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

    "myConnectionIdProperty": "$context.connectionId",
    "myQueryParams": $input.params()

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

(请注意,虽然$request 是模板选择表达式中的有效变量,但它不是模板本身的有效变量。在此处使用$input。)

【讨论】:

我按照您的指示在 cloudwatch 中看到了转换后的请求正文。但是,集成后端缺少转换后的请求正文。我已经尝试了很多事情,但被困在最后一步。你能看看吗? ***.com/questions/70738217/…【参考方案2】:

感谢大家尝试记录 AWS API Gateway。

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

    取消选中使用代理集成

    保存

    如下图设置请求模板:

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

    保存

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

    设置集成响应,如下图所示:

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

我建议忘记任何其他类型的集成,只使用 lambda。因为您将面临的下一个问题是在断开连接的集成中获取连接时传递的查询参数。

【讨论】:

我按照这些步骤操作,能够在 cloudwatch 中看到转换后的请求正文。但是,集成后端缺少转换后的请求正文。我已经尝试了很多事情,但被困在最后一步。你能看看吗? ***.com/questions/70738217/…【参考方案3】:

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

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

【讨论】:

根据本文档:docs.aws.amazon.com/apigateway/latest/developerguide/… / Route Selection Expression 部分,$request.body 可以使用,但我总是得到“”。你能解释一下为什么吗? 我按照这些步骤操作,能够在 cloudwatch 中看到转换后的请求正文。但是,集成后端缺少转换后的请求正文。我已经尝试了很多事情,但被困在最后一步。你能看看吗? ***.com/questions/70738217/…【参考方案4】:

该问题未指定使用哪种类型的后端。 AWS API Gateway 的 AWS 文档是针对 lambda 函数的——我找不到任何帮助来获取我的 http 后端的 connectionId。

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

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

路由选择表达式:$request.body.action

路由键:订阅 这意味着所有带有 "action": "subscribe" 的请求都会经过这里

集成请求类型:HTTP

HTTP 代理集成:关闭 - 到标头或身份验证通过 HTTP 方法:POST

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

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

最后一步是将其作为“订阅”的“生成模板”输入:

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

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

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

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

【讨论】:

感谢您的回答,这对我有很大帮助!你能解释一下为什么你使用$input.body而不是文档中提到的$request.body吗? 我按照接受答案的步骤,能够在 cloudwatch 中看到转换后的请求正文。但是,集成后端缺少转换后的请求正文。我已经尝试了很多东西,但被困在最后一步:***.com/questions/70738217/… 我认为你的答案是正确的,因为我意识到 API Gateway 的 WebSocket API 是面向 Lambda 函数而不是其他类型的后端集成【参考方案5】:

要解决此问题,请转到您的 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。

【讨论】:

我几乎尝试了所有方法来获取 HTTP 实现的 $connect、$disconnect 和 $default 路由中的 connectionId,但没有部署 :P 感谢提醒部署。一切都像魅力一样! 天哪!我已经尝试了上述所有其他答案,但它们不起作用,因为我试图使用在 EC2 中运行的 Express 后端。我没有意识到我应该使用 Lambda。终于你的回答当场解决了我的问题!!如果您可以简单地将您的答案粘贴到***.com/questions/70738217/…,我会接受它作为答案。 (将来可能会对某人有所帮助) @Kid_Learning_C:请不要在这里提倡复制+粘贴回答。 Stack Overflow 上删除了重复的答案。 (我们更愿意将一个问题作为另一个问题的副本来结束)。 @halfer 感谢您的提醒。您是对的-但这并不是完全重复的问题。我能做的就是将我的帖子标记为可能的重复,并将链接添加到这个答案。 完美 - 非常理想。谢谢! (但我们不会链接到问题中的答案 - 问题不应包含答案材料。)【参考方案6】:

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

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

模板选择表达式:\$default 模板键:\$default 生成模板
"connectionId": "$context.connectionId", "body": $input.body

使用此配置,您的 HTTP 端点应该使用单个路由在“action”的所有值中获取 connectionID 作为正文数据。

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

模板选择表达式:\$default 模板键:\$default 生成模板
"connectionId": "$context.connectionId"

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

【讨论】:

当我使用 \$default 进行模板选择表达式时。套接字连接未建立。 我遇到了类似的问题,最终通过进行集成响应和方法响应(如上所述)来解决它,除了允许连接正常工作之外没有任何明显的目的。【参考方案7】:

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

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

【讨论】:

【参考方案8】:

您可以从 event.requestContext 中获取 connectionId。

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

【讨论】:

以上是关于AWS API Gateway Websockets——connectionID 在哪里?的主要内容,如果未能解决你的问题,请参考以下文章

AWS API Gateway Websocket UnknownError

如果在 Terraform 模块中创建了 aws_api_gateway_integration,如何在 aws_api_gateway_deployment 资源上填充depends_on?

从AWS API-Gateway中找出lambda名称

响应未定义 - aws-api-gateway-client

从 VPC 内将“禁止”异常发布到 API Gateway Websocket API

AWS API Gateway:用户匿名无权执行 API