Muhammad Asad
Muhammad Asad

Reputation: 55

Angular app not able to communicate with Flask via Socket.IO

I am working on an Angular project that involves communicating with Flask via SocketIO. Unfortunately, I am a complete beginner at python and Flask though have tried all that I could understand. This far I have tried involving CORS as can be seen in the code and also Zachary Jacobi's solution mentioned in

Javascript - No 'Access-Control-Allow-Origin' header is present on the requested resource

However, I am still getting the errors

Access to XMLHttpRequest at 'http://localhost:5000/socket.io/?EIO=3&transport=polling&t=NDLi66V' from origin 'http://localhost:4200' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

GET http://localhost:5000/socket.io/?EIO=3&transport=polling&t=NDLi66V net::ERR_FAILED

The Flask code that I am using is


from flask import Flask, render_template
from flask_socketio import SocketIO
from flask_cors import CORS
from corsAlt import crossdomain

import json

app = Flask(__name__)
CORS(app)
#app.config['SECRET_KEY'] = 'vnkdjnfjknfl1232#'

socketio = SocketIO(app)

@app.route('/')

@crossdomain(origin='*')

def sessions():
    return render_template('index.html')


def messageReceived(methods=['GET', 'POST']):
    print('message was received!!!')

@socketio.on('my event')
def handle_my_custom_event(json, methods=['GET', 'POST']):
    json["user_name"]='Asad'
    json["user_input"]='My Server'
    print('received my event: ' + str(json))
    socketio.emit('my response', json, callback=messageReceived)


if __name__ == '__main__':
    socketio.run(app, debug=True, host='localhost', port = 5000)

In the Angular side,

    import { Sio2service } from '../sio2.service';
        @Component({
      selector: 'app-workout-options',
      templateUrl: 'workout-options.component.html',
      styleUrls: ['../app.component.css']
    })
    export class WorkoutOptionsComponent implements OnDestroy{
        mymessage: string;
        subscription: Subscription;

        @Output() public childEvent = new EventEmitter();
            constructor(private messageService: MessageService, private sio2: Sio2service) {
            this.subscription = this.messageService.getMessage()
            .subscribe(mymessage => {
                this.mymessage = mymessage;
            });
        }
 
        OnInit(){
            this.sio2.messages.subscribe(msg => {
        })
        }
        FupdateParent(exerName:string) {
            this.sio2.sendMsg(exerName);
        }
}

Where the SIO and SIO2 codes are

import { Injectable } from '@angular/core';
import * as io from 'socket.io-client';
import { Observable } from 'rxjs/Observable';
import * as Rx from 'rxjs/Rx';
import { environment } from '../environments/environment';
@Injectable({
  providedIn: 'root'
})
export class Sioservice {
 private socket;
  constructor() { }
connect(): Rx.Subject<MessageEvent> {
    // If you aren't familiar with environment variables then
    // you can hard code `environment.ws_url` as `http://localhost:5000`
    this.socket = io(environment.ws_url);

    // We define our observable which will observe any incoming messages
    // from our socket.io server.
    let observable = new Observable(observer => {
        this.socket.on('message', (data) => {
          console.log("Received message from Websocket Server")
          observer.next(data);
        })
        return () => {
          this.socket.disconnect();
        }
    });

    // We define our Observer which will listen to messages
    // from our other components and send messages back to our
    // socket server whenever the `next()` method is called.
    let observer = {
        next: (data: Object) => {
            this.socket.emit('message', JSON.stringify(data));
        },
    };

    // we return our Rx.Subject which is a combination
    // of both an observer and observable.
    return Rx.Subject.create(observer, observable);
  }

}

import { Injectable } from '@angular/core';
import { Sioservice } from './sio.service';
import { Observable, Subject } from 'rxjs/Rx';

@Injectable({
  providedIn: 'root'
})
export class Sio2service {

messages: Subject<any>;

  // Our constructor calls our wsService connect method
  constructor(private wsService: Sioservice) {
    this.messages = <Subject<any>>wsService
      .connect()
      .map((response: any): any => {
        return response;
      })
   }

  // Our simplified interface for sending
  // messages back to our socket.io server
  sendMsg(msg) {
    this.messages.next(msg);
  }
}

Please note that the Angular app communicates smoothly with the app.js file as


let app = require("express")();
let http = require("http").Server(app);
let io = require("socket.io")(http);

io.on("connection", socket => {
  // Log whenever a user connects
  console.log("user connected");

  // Log whenever a client disconnects from our websocket server
  socket.on("disconnect", function() {
    console.log("user disconnected");
  });

  // When we receive a 'message' event from our client, print out
  // the contents of that message and then echo it back to our client
  // using `io.emit()`
  socket.on("message", message => {
    console.log("Message Received: " + message);
    io.emit("message", { type: "new-message", text: message });
  });
});

// Initialize our websocket server on port 5000
http.listen(5000, () => {
  console.log("started on port 5000");
});

But the problem I am having with that is that I cannot get it to communicate with app.js above as it seems to create its own server.

Upvotes: 0

Views: 842

Answers (1)

Ashish Kumar Jaryal
Ashish Kumar Jaryal

Reputation: 812

You need three things in the response header to solve CORS issue:

  1. response.headers.add("Access-Control-Allow-Origin", "*")
  2. response.headers.add('Access-Control-Allow-Headers', "*")
  3. response.headers.add('Access-Control-Allow-Methods', "*")

I am not aware of how Flask works but I can guess that you are only handling number 1 point: crossdomain(origin='*')

Side note: Number 3 point is used in case of pre flight requests with OPTIONS verb.

To help you, I copied a part of code from the link of question you pasted in your question:

@app.after_request
    def after_request(response):
      response.headers.add('Access-Control-Allow-Origin', '*')
      response.headers.add('Access-Control-Allow-Headers', 'Content-Type,Authorization')
      response.headers.add('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS')
      return response

Upvotes: 0

Related Questions