centrifugal/centrifuge-js

Angular app fails to connect to Centrifuge WebSocket

hamedaravane opened this issue · 3 comments

Hi there!
I hope this message finds you well.
I'm currently facing an issue connecting to a centrifuge server in an Angular application. The transport gets closed immediately after I send the connection request.
I've gone through all the open issues in this repository and tried the suggested solutions, but unfortunately, the problem persists.

Summary:

  • Angular app cannot connect to centrifuge server.
  • WebSocket transport closes immediately after trying to connect.
  • Issue does not occur in Postman.

Details:

  • CentrifugeAbstract class wraps centrifuge methods.
  • Websocket class extends CentrifugeAbstract and connects to Centrifuge with a specific URL.
  • init method in Websocket is called to connect and subscribe to a channel.
  • Logs show that connection and subscription requests are sent.
  • Error "WebSocket connection to '' failed: WebSocket is closed before the connection is established." occurs.
  • "transport closed" error with code 2 is seen in client error.
import {Injectable} from "@angular/core";
import { Centrifuge, Subscription } from 'centrifuge';

@Injectable({
  providedIn: "root"
})
export abstract class CentrifugeAbstract {
  protected abstract client: Centrifuge;

  protected connect(): void {
    this.client.on('connecting', (ctx) => {
      console.log('connecting', ctx);
    });

    this.client.on('connected', (ctx) => {
      console.log('connected', ctx);
    });

    this.client.on('disconnected', (ctx) => {
      console.log('disconnected', ctx);
    });

    this.client.on('error', (ctx) => {
      console.warn('client error', ctx);
    });

    this.client.connect();
  }

  protected subscribe(channel: string, data?: any) {
    const sub: Subscription = this.client.newSubscription(channel, {data});

    sub.on('subscribing', (ctx) => {
      console.log('subscribing', ctx);
    });

    sub.on('subscribed', (ctx) => {
      console.log('subscribed', ctx);
    });

    sub.on('unsubscribed', (ctx) => {
      console.log('unsubscribed', ctx);
    });

    sub.on('publication', (ctx) => {
      console.log('publication', ctx);
    })

    sub.subscribe();
  }

  // other methods...
@Injectable({
  providedIn: "root"
})
export class DashboardFacade extends CentrifugeAbstract {
  protected client = new Centrifuge(environment.streamBaseUrl);

  initWebSocket() {
    this.connect();
    this.subscribe('<channel>');
  }
}
@Component({
  ...
})
export class DashboardComponent implements OnInit {
  private readonly dashboardFacade = inject(DashboardFacade);

  ngOnInit() {
    this.dashboardFacade.initWebSocket();
  }
}

Chrome Developer Console:

connecting: {
  "code": 0,
  "reason": "connect called"
}

subscribing: {
  "channel": "<channel>",
  "code": 0,
  "reason": "subscribe called"
}

WebSocket connection to '<URL>' failed: WebSocket connection to '<URL>' failed: WebSocket is closed before the connection is established.

client error: {
  "type": "transport",
  "error": {
    "code": 2,
    "message": "transport closed"
  },
  "transport": "websocket"
}

Actions Taken:

  • Checked all open issues in this repository
  • Tested websocket URL in Postman successfully

Request:

Solution for the websocket transport closing issue

Note

WebSocket URL has been removed for security reasons.

Environment:

Operating system: macOs Sonoma 14.2.1
Browser: Google Chrome 123.0.6312.59 (Official Build) (x86_64)
Angular version: 17.2.0
Centrifuge version: 5.0.2

Thank you for your time and assistance.

Hello @hamedaravane ,

Check out Centrifugo server logs, often the reason is described there. Possibly the reason is misconfigured allowed_origins option in Centrifugo configuration.

Hi @FZambia,
Thanks for your response. I don't have access to the centrifuge server, so I can't check its logs.
Is there a way to handle this issue like CORS in REST API? For example, can we set up a proxy or are there other solutions?

I really appreciate your time and help.

I am not 100% sure you get allowed origins problem. If yes – I think you can try proxy approach though it may be more difficult than with HTTP-based CORS since WebSocket is less common, and I personally never did this myself so can't recommend something. If you connect from the backend environment, the next thing you may come across when connecting is connection authentication - JWT or Cookie-based, depends on Centrifugo configuration. What is the use case where you don't have access to server BTW?