WebSockets Proxy using Socket.io-client in create-react-app

Viewed 4304

I'm trying to add a proxy to my react app for socket.io-client

I'm using setupProxy.js with http-proxy-middleware which works fine for APIs but not for sockets

Server code with node js

var app = require('express')();
var http = require('http').createServer(app);
var io = require('socket.io')(http);

app.get('/', function (req, res) {
  res.sendFile(__dirname + '/index.html');
});

io.on('connection', function (socket) {
  setInterval(() => {
    console.log('emit event');
    io.emit('event', { data: 'worked successfully!' });
  }, 1000);
});

http.listen(8080, function () {
  console.log('listening on *:8080');
});

Client code with react

function App() {
  const socket = socketIOClient('/', {
    transports: ['websocket'],
  });

  useEffect(() => {
    socket.on('connect', () => {
      console.log('connected');
    });
    socket.on('event', (data) => {
      console.log(data);
    });

  }, []);
  return (
    <div className='App'>
     Socket Proxy test
    </div>
  );
}

and my setupProxy.js

const { createProxyMiddleware } = require('http-proxy-middleware');

module.exports = (app) => {
  app.use(
    '/socket.io',
    createProxyMiddleware({
      target: 'http://localhost:8080',
      changeOrigin: true,
      ws: true, // enable websocket proxy
      logLevel: 'debug',
    })
  );
};
2 Answers

I resolved the problem by adding custom path in both server and client socket options

{
  path: '/socket',
}

and then use that path in proxy middleware

  const socketProxy= createProxyMiddleware('/socket', {
    target: 'http://localhost:8080',
    changeOrigin: true,
    ws: true, 
    logLevel: 'debug',
  });

  app.use(socketProxy);

so final working code should look something like this :

Server code :

var app = require('express')();
var http = require('http').createServer(app);
var io = require('socket.io')(http, {
  path: '/socket', // added this line of code
});

app.get('/', function (req, res) {
  res.sendFile(__dirname + '/index.html');
});

io.on('connection', function (socket) {
  setInterval(() => {
    console.log('emit event');
    io.emit('event', { data: 'worked successfully!' });
  }, 1000);
});

http.listen(8080, function () {
  console.log('listening on *:8080');
});

Client code :

function App() {
  const socket = socketIOClient('/', {
      transports: ['websocket'],
      path: '/socket', // added this line of code
  });

  useEffect(() => {
    socket.on('connect', () => {
      console.log('connected');
    });
    socket.on('event', (data) => {
      console.log(data);
    });

  }, []);
  return (
    <div className='App'>
     Socket Proxy test
    </div>
  );
}

Note: namespace should be added in <URL> param : const socket = socketIOClient('/namespace', {...})

and final setupProxy.js

const { createProxyMiddleware } = require('http-proxy-middleware');

module.exports = (app) => {
  const socketProxy= createProxyMiddleware('/socket', {
    target: 'http://localhost:8080',
    changeOrigin: true,
    ws: true, 
    logLevel: 'debug',
  });

  app.use(socketProxy);
};

I solved this problem in these steps:

  1. Create SocketIO client using http protocol.

Frontend:

import io from 'socket.io-client';

const socket = io({
    protocols: ["http"],
});
  1. Create a ProxyMiddleware in setupProxy.js.
module.exports = function (app) {
    app.use(
        createProxyMiddleware("/socket.io",{
            target: 'http://localhost:8001',
            changeOrigin: true,
            ws: false,
        })
    );
};

Note:

  1. socket.io-client's default endpoint is /socket.io.
  2. socket.io-client's default protocol is ws://, this will not trigger proxy rules by defulat.
Related