在 create-react-app 中使用 Socket.io-client 的 WebSockets 代理

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

我正在尝试为 socket.io-client

向我的 React 应用程序添加代理

我将 setupProxy.jshttp-proxy-middleware 一起使用,它适用于 API,但不适用于套接字

带有节点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');
});

带有反应的客户端代码

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>
  );
}

和我的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',
    })
  );
};

我通过在服务器和客户端套接字选项中添加自定义路径解决了这个问题

{
  path: '/socket',
}

然后在代理中间件中使用该路径

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

  app.use(socketProxy);

所以最终的工作代码应该是这样的:

服务器代码:

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');
});

客户代码:

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', {...})

和最后的 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);
};

我通过以下步骤解决了这个问题:

  1. 使用 http protocol 创建 SocketIO 客户端。

前端:

import io from 'socket.io-client';

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

:

  1. socket.io-client 的默认端点是 /socket.io.
  2. socket.io-client的默认协议是ws://,默认不会触发代理规则。