I am trying to connect to a SignalR hub behind an Ocelot Api gateway from a React application. However, when doing so I get the following error:
Unhandled Rejection (Error):
new HttpError
index.js:1 [2021-01-31T02:42:31.498Z] Error: Failed to complete negotiation with the server: Error
index.js:1 [2021-01-31T02:42:31.498Z] Error: Failed to start the connection: Error
Uncaught (in promise) Error
at new HttpError (Errors.ts:20)
at FetchHttpClient.<anonymous> (FetchHttpClient.ts:116)
at step (FetchHttpClient.ts:2)
at Object.next (FetchHttpClient.ts:2)
at fulfilled (FetchHttpClient.ts:2)
I have read Ocelot's documentation on SignalR/WS (https://ocelot.readthedocs.io/en/latest/features/websockets.html) and also made sure that requests are being routed as they should in my ocelot.json:
{
"DownstreamPathTemplate": "/notificationhub",
"DownstreamScheme": "ws",
"DownstreamHostAndPorts": [
{
"Host": "localhost",
"Port": 7001
}
],
"UpstreamPathTemplate": "/notifications",
"UpstreamHttpMethod": [ "GET", "POST", "PUT", "DELETE", "OPTIONS" ]
},
What is wrong?
First of all, web sockets secure (wss), which is not mentioned in the Ocelot documentation, can be used as DownStreamScheme as pointed out by sam9291 here (https://github.com/ThreeMammals/Ocelot/issues/1179).
Secondly, Cors must be enabled on the SignalR app with AllowCredentials() as detailed by Microsoft here (https://learn.microsoft.com/en-us/aspnet/core/signalr/security?view=aspnetcore-5.0).
Thirdly, there has to be a {catchAll} route in the ocelot.json, which is necessary becausse the handshake involves getting/posting to other routes:
{
"DownstreamPathTemplate": "/notificationhub/{catchAll}",
"DownstreamScheme": "ws",
"DownstreamHostAndPorts": [
{
"Host": "localhost",
"Port": 7001
}
],
"UpstreamPathTemplate": "/notifications/{catchAll}",
"UpstreamHttpMethod": [ "GET", "POST", "PUT", "DELETE", "OPTIONS" ]
},
Fourthly, when I tried requesting /notifications after the above change I got error 404, not sure if it is a bug or a feature, like the issue LilRazi ran into here (ocelot: 404 error when add extra path on upstream url). So then I just added a route for the /notifications part, like so:
{
"DownstreamPathTemplate": "/notificationhub",
"DownstreamScheme": "ws",
"DownstreamHostAndPorts": [
{
"Host": "localhost",
"Port": 7001
}
],
"UpstreamPathTemplate": "/notifications",
"UpstreamHttpMethod": [ "GET", "POST", "PUT", "DELETE", "OPTIONS" ]
},
and everything was working perfectly!