UnrealEngineのWebSocketsモジュールを利用してAWSのAPI Gatewayのwebsocketとパスなしのカスタムドメインで通信できなくてはまったので内容を記録しておきます。
確認した環境
Windows 11
UE5.2.1
WebSocketsモジュールについて
build.csにPrivateDependencyModuleNamesにWebSocketsを追加し、以下のようなコードでWebSocket通信ができます。
#include "WebSocketsModule.h"
#include "IWebSocket.h"
[略]
TSharedRef<IWebSocket> Socket = FWebSocketsModule::Get().CreateWebSocket(ServerURI, ServerProtocol, Headers);
Socket->OnConnected().AddUObject(this, &UWebSocketClient::OnConnected);
Socket->OnConnectionError().AddUObject(this, &UWebSocketClient::OnConnectError);
Socket->OnClosed().AddUObject(this, &UWebSocketClient::OnClosed);
Socket->OnMessage().AddUObject(this, &UWebSocketClient::OnMessage);
Socket->Connect();
[略]
//が追加される現象について
wss://api.example.comのようなパスのないURLを指定してCreateWebSocketしてConnectすると以下のような結果になりました。
- エラーになって以下のようなログが記録される
LogWebSockets: Warning: Lws(Warning): lws_client_handshake: got bad HTTP response '400'
LogWebSockets: Verbose: FLwsWebSocket[1]::LwsCallback: Received LWS_CALLBACK_CLIENT_CONNECTION_ERROR, setting State=Error CloseReason=HS: ws upgrade response not 101 PreviousState=Connecting
- API Gatewayのアクセスログには何も記録されない
- fiddlerでは以下のような通信が記録されレスポンスとして400エラーになっている
GET https://api.example.com// HTTP/1.1
[略]
Upgrade: websocket
Connection: Upgrade
[略]
原因
デバッグするとURLを解析するlibwebsocketsのlws_parse_uri関数の結果、パスの文字列が/になっておりそれと/がジョインされることで//になっていました。
https://github.com/EpicGames/UnrealEngine/blob/release/Engine/Source/Runtime/Online/WebSockets/Private/Lws/LwsWebSocket.cpp#L709-L728
/hogeなどのパスが指定されている場合のlws_parse_uri関数で解析されるパスの文字列はhogeになっています。
libwebsocketsとしては仕様みたいです。
https://github.com/warmcat/libwebsockets/issues/414
対策
Engineの改造は嫌だったので、API Gatewayのカスタムドメインをパス付で提供するように変更しました。
所感
API Gatewayがデフォルトで提供するドメインはステージのパス付なので問題なく通信ができていたので、カスタムドメインに書き換えるだけと思っていたらできなくてはまりました。
ログを見ると400エラーが返って失敗しているようなのにAPI Gateway側にログが記録されていないというのでしばらく悩みました。