centrifugal / centrifuge-js

JavaScript client SDK to communicate with Centrifugo and Centrifuge-based server from browser, NodeJS and React Native. Supports WebSocket, HTTP-streaming over Fetch and Readable Stream API, EventSource, WebTransport.
https://centrifugal.dev
MIT License
411 stars 104 forks source link

Angular app fails to connect to Centrifuge WebSocket #273

Closed hamedaravane closed 8 months ago

hamedaravane commented 8 months ago

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:

Details:

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:

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.

FZambia commented 8 months ago

Hello @hamedaravane ,

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

hamedaravane commented 8 months ago

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.

FZambia commented 8 months ago

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?