fix(signalr): skip negotiate, connect WebSockets-only (CDN 404s the POST)
CI/CD / CI - API (dotnet build + engine sim) (push) Successful in 50s
CI/CD / CI - Web (tsc + next build) (push) Successful in 1m8s
CI/CD / Deploy - local stack (db + server + web) (push) Successful in 1m0s

WCDN rejects the SignalR negotiate POST (404, wcdn-nfc-reason: Http_Method), so
the hub never connects and online matchmaking never starts. Connect directly via
WebSockets with skipNegotiation so there's no negotiate POST; the JWT rides the
?access_token query the server already accepts for /hub. The proper fix remains
bypassing the CDN for api.bargevasat.ir.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
soroush.asadi
2026-06-15 17:53:16 +03:30
parent 76c4b68a74
commit 21fd5c123e
+9 -1
View File
@@ -141,7 +141,15 @@ export class SignalrService implements OnlineService {
private async connect(): Promise<void> { private async connect(): Promise<void> {
if (this.conn || !this.token) return; if (this.conn || !this.token) return;
const conn = new signalR.HubConnectionBuilder() const conn = new signalR.HubConnectionBuilder()
.withUrl(`${SERVER}/hub/game`, { accessTokenFactory: () => this.token ?? "" }) // Connect straight over WebSockets and SKIP the negotiate POST — some CDNs
// (WCDN) 404 the negotiate POST by method. The JWT rides the WS query
// string (server reads ?access_token for /hub). Real fix is to bypass the
// CDN for api.bargevasat.ir; this is a best-effort fallback.
.withUrl(`${SERVER}/hub/game`, {
accessTokenFactory: () => this.token ?? "",
skipNegotiation: true,
transport: signalR.HttpTransportType.WebSockets,
})
.withAutomaticReconnect() .withAutomaticReconnect()
.configureLogging(signalR.LogLevel.Warning) .configureLogging(signalR.LogLevel.Warning)
.build(); .build();