1

I've used cors for my express server, but I can't figure out why it's not working. Can anyone please help me with this issue?

Access to XMLHttpRequest at 'https://tic-tac-toe-server.now.sh/socket.io/?EIO=3&transport=polling&t=N6Z2b4X' from origin 'http://localhost:8080' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

Client:

import io from 'socket.io-client';
const socket = io('https://tic-tac-toe-server.now.sh')

Here is my index.js

const express = require('express');
const socketio = require('socket.io');
const http = require('http');
const cors = require('cors');


const router = require('./router');
const { addUser, removeUser, getUsers } = require('./users');
const { getMatch, addPlayer, destroyMatch } = require('./players');

const PORT = process.env.PORT || 5000;

const app = express();
const server = http.createServer(app);


const io = socketio(server);

app.use(router);
app.use(cors());


io.on('connection', function (socket) {
    const id = socket.id;
    let user_room = '';

    /**
     * User Joins to the global room
     */
    socket.on('join', function ({ name, room, playing = false }) {
        addUser({ id, name, room, playing }); // add user to users array
        user_room = room;
        socket.join(user_room);
        socket.join(id);
        socket.emit('user_joined', getUsers());
        socket.broadcast.emit('user_joined', getUsers()); // emit event with modified users array
    });

    /**
     * Match Started
     */

    socket.on('player_joined', user => {
        const match = getMatch();
        addPlayer(user.match, user);
        if(match.hasOwnProperty(user.match) && match[user.match].length === 2){
            socket.emit('player_joined', match[user.match]);
            socket.broadcast.to(user.match).emit('player_joined', match[user.match]);
        }
    });

    socket.on('move', (data) => {
        socket.emit('move', data);
        socket.broadcast.to(data.match).emit('move', data);
    });

    socket.on('emote', (data) => {
        socket.emit('emote_from', data);
        socket.broadcast.to(data.match).emit('emote_to', data);
    });


    /**
     * On user challenge
     */


    socket.on('challenge', (socketId) => {
        io.to(socketId).emit('accept', id);
    });

    socket.on('rejected', (socketId) => {
        io.to(socketId).emit('rejected', id);
    });

    socket.on('accepted', data => {
        io.to(data.opponent.id).emit('accepted', data);
        socket.emit('accepted', data);
    });

    socket.on('player_left_match', match => {
        socket.broadcast.to(match).emit('player_left_match');
    });

    socket.on('destroy_match', match => {
        destroyMatch(match);
    });

    /**
     * User Disconnect function
     */
    socket.on('disconnect', () => {
        socket.leave(user_room);
        socket.leave(id);
        removeUser(id); // remove user form users array
        socket.emit('user_left', getUsers());
        socket.broadcast.emit('user_left', getUsers());  // emit event with modified users
    })


});

server.listen(PORT, () => console.log(`Server running on port ${PORT}`));
Delowar Hosain
  • 2,214
  • 4
  • 18
  • 35
  • One solution here: [socket.io not connecting due to CORs error](https://stackoverflow.com/questions/61047220/socket-io-and-express-app-not-connecting-due-to-cors-error-the-value-of-the-a/61051698#61051698). – jfriend00 Apr 22 '20 at 18:14
  • @jfriend00 Thanks for your comment, I didn't understand this answer, can you please give me an example code? – Delowar Hosain Apr 22 '20 at 18:26
  • For more specific help in that direction, add your client socket.io connection code to the question. That's where the above change would be made. – jfriend00 Apr 22 '20 at 18:28
  • @jfriend00 I've added my client connection code. – Delowar Hosain Apr 22 '20 at 18:30

1 Answers1

4

You can tell socket.io to only use the webSocket transport which is not subject to CORS by changing this:

const socket = io('https://tic-tac-toe-server.now.sh')

to this:

const socket = io('https://tic-tac-toe-server.now.sh', {transports: ['websocket']});

Some background. In its default configuration, socket.io starts every connection with multiple plain http requests. These plain http requests require server-side CORS support if the connection is cross-origin. But, socket.io can be configured to go straight to the webSocket transport (which is what is eventually ends up using anyway) and webSocket connections are not subject to CORS limitations.

The socket.io design to start with http polling was largely there because in the early days of webSocket support, not every browser supported it and not every server infrastructure supported it. But now-a-days, it is pretty widely supported.

So, telling socket.io to start with the webSocket transport from the beginning avoids many potential CORS issues.


We are now chasing a different issue and the error showing in the console at https://tic-tac-toe-vue.now.sh/ is coming from this code in webSocket.js.

  try {
    this.ws =
      this.usingBrowserWebSocket && !this.isReactNative
        ? protocols
          ? new WebSocketImpl(uri, protocols)
          : new WebSocketImpl(uri)
        : new WebSocketImpl(uri, protocols, opts);
  } catch (err) {
    return this.emit('error', err);
  }

It looks like something React related since there's a reference to isReactNative, but since your code is packaged and minimized, it's not very easy to do any debugging from here.

jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • Getting another error with this code: WebSocket connection to 'wss://tic-tac-toe-server.now.sh/socket.io/?EIO=3&transport=websocket' failed: Error during WebSocket handshake: Unexpected response code: 404 – Delowar Hosain Apr 22 '20 at 18:50
  • 1
    @DelowarHosain - Your client code shows an https connection. Your server code shows an http server. Can't connect to an http server with https. That fact that you're getting a 404 means there is indeed a server on https, but it doesn't look like it's the one you show the code above for. – jfriend00 Apr 22 '20 at 18:54
  • I deployed to the https server, still getting this error: https://tic-tac-toe-vue.now.sh/ – Delowar Hosain Apr 22 '20 at 19:07
  • 1
    @DelowarHosain - That is apparently something else (note its a completely different error). The code you show in your question wouldn't do that all by itself. One possible guess is that you have a mismatched version of socket.io between client and server. Unfortunately, your code appears to be packaged and minimized on that website so it's a pain to try to debug. I can't even find where you use socket.io on page. See what I added to the end of my answer. – jfriend00 Apr 22 '20 at 19:17
  • Both the client & server versions are the same. Server/Root: https://github.com/delowardev/tic-tac-toe Vue Client: https://github.com/delowardev/tic-tac-toe/tree/dev/vue-client Bty thanks a lot for helping me <3 – Delowar Hosain Apr 22 '20 at 19:20
  • @DelowarHosain - Are you 100% sure same version. It appears the client is getting socket.io from `socket.io-client` which means it's not getting the automatic same version from the server (which publishes a matching version for you to use). I'm going to have to leave the rest of your problem to someone else who knows something about your client-side environment. I can't find my way around this type of project. Since I answered your CORS issue, perhaps you should open a new question about whatever different issue remains. – jfriend00 Apr 22 '20 at 19:32
  • @DelowarHosain - Is your connection on the deployed version going through any sort of proxy that might need to be webSocket enabled? – jfriend00 Apr 22 '20 at 19:32
  • I think the problem is `now.sh` server, I deployed node server file on the Heroku, now it's working fine. https://tic-tac-toe-vue.now.sh/ – Delowar Hosain Apr 24 '20 at 06:09
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/212397/discussion-between-delowar-hosain-and-jfriend00). – Delowar Hosain Apr 24 '20 at 06:11