Search code examples
c#reactjssignalrasp.net-core-signalrocelot

Unhandled Rejection (Error) (HttpError) when connecting to SignalR hub in Ocelot Api Gateway via React Client Application


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?


Solution

  • 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!