Amazon-API-Gateway

WebSocketのAPI Gatewayでバックエンド側のLambdaからPOSTする際のエラーを解消する2

はじめに

こんにちは、omkです。
この連休の間はAPI GatewayのWebSocket APIで遊んでいたのですが、前回とは異なるエラーが出たので備忘を兼ねて対処方法を載せていきます。

Lambdaはプロキシ統合しています。

事象1

LambdaでAPIへのコネクションに対してPOSTを行おうとした際にエラーが以下のエラーが出ました。

An error occurred (GoneException) when calling the PostToConnection operation:

問題の発生したLambdaのコード

各コネクションIDをDynamoDBに記録しておき、Lambdaからスキャンして全員にメッセージを送ります。

(略)
users = dynamo_table.scan();

client = boto3.client(service_name='apigatewaymanagementapi',endpoint_url = "wss://{API}.execute-api.ap-northeast-1.amazonaws.com/production")

message = { "message": "hoge" }

for connection in users['Items']:
    response = client.post_to_connection(
        Data=json.dumps(message),
        ConnectionId=connection['connectionId']
    )
(略)

エラーハンドリングなどは内容が見やすいように省いてます。

内容

An error occurred (GoneException) when calling the PostToConnection operation:

このエラーはAWSのre:Postにも記載がありました。

接続が確立される前に WebSocket API にメッセージが投稿された。
接続が終了したか、もう存在していない。
クライアントが接続を切断し、同じ connectionId を使用して再接続しようとした。

が原因とのことです。
今回とは別の検証でしたがDynamoDBに格納しているConnectionIDがクライアントの切断時に削除されていなかったときにも遭遇しました。
foreachで全体にメッセージを送るケースではここの対応は基本的に必要だと思います。

ですが、なんと今回はコピペによる凡ミスでメッセージの「endpoint_url」に指定するAPIを誤って別のWebSocket APIのもので指定していました。
APIは存在するのにコネクションIDが存在しないということで上記のケースと同じ状況になっていました。
確認はしっかりしようね。てへぺろ。

事象2

API GatewayのURLを作成したものに指定し直して接続してみたところエラーが変わりました。

Could not connect to the endpoint URL: "https://execute-api.ap-northeast-1.amazonaws.com/@connections/{コネクションID}"

エンドポイントに接続できないとのこと。

問題の発生したLambdaのコード

先程と変わらないので読み飛ばしてください。

(略)
users = dynamo_table.scan();

client = boto3.client(service_name='apigatewaymanagementapi',endpoint_url = "wss://{API}.execute-api.ap-northeast-1.amazonaws.com/production")

message = { "message": "hoge" }

for connection in users['Items']:
    response = client.post_to_connection(
        Data=json.dumps(message),
        ConnectionId=connection['connectionId']
    )
(略)

内容

https://execute-api.ap-northeast-1.amazonaws.com/@connections/{コネクションID}

APIのURLの指定がおかしくなっていますね。
API作成時に発行されるURLは以下のような形式で発行されます。

WebSocket URL: wss://hogehoge.execute-api.ap-northeast-1.amazonaws.com/production
接続 URL: https://hogehoge.execute-api.ap-northeast-1.amazonaws.com/production

hogehogeで書いた部分がすっぱり失くなっています。

別に書き忘れたとかではなくて、APIのURLの指定をwssから始まるURLで指定しているとこうなりました。
自動でhttpsのURLに書き換えられて処理されるみたいですがそのときにいつの間にかhogehoge部が消えるみたいです。
ドキュメントの記載がないので明確なことは分からないですが、そもそも@connectionsコマンドを利用するにはhttpsの接続URLを利用する必要があるようですね。

@connectionsコマンドについてはこちらを参照
https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/apigateway-how-to-call-websocket-api-connections.html

HTTPSでURLを指定するように変更したところ直りました。

事象3

HTTPSのURLを指定したところ次のエラーが出ました。

An error occurred (NotFoundException) when calling the PostToConnection operation: No method found matching route @connections/@connections/{コネクションID} for http method POST

メソッドにマッチするルートが無いとのこと。

問題の発生したLambdaのコード

APIのエンドポイントURLを変更しました。

(略)
users = dynamo_table.scan();

client = boto3.client(service_name='apigatewaymanagementapi',endpoint_url = "https://{API}.execute-api.ap-northeast-1.amazonaws.com/production/")

message = { "message": "hoge" }

for connection in users['Items']:
    response = client.post_to_connection(
        Data=json.dumps(message),
        ConnectionId=connection['connectionId']
    )
(略)

内容

エンドポイントURLの最後のスラッシュ有り無しの問題でした。
「/production」のAPIへの実行を「/production/」に指定してしまったことで問題が生じていました。

@connections/@connections/{コネクションID}

post_to_connectionでは指定のエンドポイントURLに対して「/@connections/{コネクションID}」にポストしてくれますが、エンドポイントURLがスラッシュで終わっている場合には@connectionsを補完してくれるようで
「@connections/@connections/{コネクションID}」に繋ぎに行って変な感じのエラーとなっていました。

前述の通り、スラッシュを除くことで正常に動作しました。

おわりに

いざまとめてみるとちょいミスシリーズになっていましたが、こういうちょいミスはやってみて始めて気付くので良い経験ですね。
WebSocket APIは触っていて楽しいのでどんどん使っていきたいです。

以上、最後までお付き合いありがとうございました。

返信を残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA