在 AWS lambda 和 API 网关上调用 post_to_connection 时出现异常

GoneException when calling post_to_connection on AWS lambda and API gateway

我想在连接到 AWS lambda 和 API 网关上的服务器时向 websocket 客户端发送消息。目前,我使用 wscat 作为客户端。由于当我连接到服务器时,wscat 控制台上没有显示响应 'connected',因此我添加了 post_to_connection 以向客户端发送消息 'hello world'。但是,它引发了 GoneException。

An error occurred (GoneException) when calling the PostToConnection operation

如何解决这个问题并在连接到服务器时向 wscat 发送一些消息?

我的 python 代码如下。我使用 Python 3.8.5.

import os
import boto3
import botocore

dynamodb = boto3.resource('dynamodb')
connections = dynamodb.Table(os.environ['TABLE_NAME'])

def lambda_handler(event, context):
    domain_name = event.get('requestContext',{}).get('domainName')
    stage       = event.get('requestContext',{}).get('stage')
    connection_id = event.get('requestContext',{}).get('connectionId')
    result = connections.put_item(Item={ 'id': connection_id })

    apigw_management = boto3.client('apigatewaymanagementapi',
                            endpoint_url=F"https://{domain_name}/{stage}")
    ret = "hello world";

    try:
      _ = apigw_management.post_to_connection(ConnectionId=connection_id,
                                             Data=ret)
    except botocore.exceptions.ClientError as e:
      print(e);
      return { 'statusCode': 500,
                    'body': 'something went wrong' }

    return { 'statusCode': 200,
             "body": 'connected'};

我发现当启动 websocket 的客户端与套接字断开连接并且不再能找到其 connectionId 时,可能会发生 GoneException。是否有什么原因导致原始客户端在收到您的 return 消息之前与套接字断开连接?

我的用例不同,但我基本上是使用数据库在回复连接之前检查连接状态,而不是使用请求上下文来执行此操作。通过在连接时将 connectionIds 写入 DynamoDB,并在断开连接事件时从 table 中删除它们,减少了此错误的出现。消息现在写入 table 中的 connectionIds 而不是请求上下文中的 id。大多数消息都通过了,但是当客户端离开套接字但没有发出适当的断开连接事件时,仍然会发出一些错误,这会在 table 中留下孤儿。下一步是在发生不规则断开连接时强制执行项目删除。涉及 DB 对你的情况来说可能有点矫枉过正,只是分享帮助我在 GoneException 错误上取得进展的东西。

自我回答:您不能 post_to_connection 到 onconnect 中的连接本身。

连接后需要post连接(即当routeKey不是$connect时)

routeKey = event.get('requestContext', {}).get('routeKey')
print(routeKey)  # for debugging 

if routeKey != '$connect':  # if we have defined multiple route keys we can choose the right one here
  apigw_management.post_to_connection(ConnectionId=connection_id, Data=ret)