用户登录时重新连接套接字

Reconnect socket on user login

我使用由 create-react-app 创建的设置并使用 flux 进行数据管理,应用程序需要在客户端实现套接字(为此我使用 socket.io)。

目前,套接字在 Socket.js 文件中按以下方式初始化:

import io from 'socket.io-client';
import { remoteUrl } from './constants/RemoteUrl';
import SocketWorker from './utilities/SocketWorker';

let socket = io.connect(remoteUrl + '?role=user');

socket.on('statusChange', (data) => {
  return SocketWorker.receiveOrderStatusChange(data);
})

export  { socket };

它确实有效,但问题是它只在加载站点时尝试连接到服务器一次。当用户打开未经身份验证的站点时,它没有连接并且错过了重新连接,因此没有建立连接并且没有收到套接字事件

我尝试创建一个 class 并响应 API 以重新连接对象,例如:

import io from 'socket.io-client';
import { remoteUrl } from './constants/RemoteUrl';
import SocketWorker from './utilities/SocketWorker';

function Socket() {
  this.socket = io.connect(remoteUrl + '?role=user');
  this.reconnect = () => {
    this.socket = io.connect(remoteUrl + '?role=user');
  }
}

let socket = new Socket();

socket.socket.on('statusChange', (data) => {
  return SocketWorker.receiveOrderStatusChange(data);
})

export { socket };

我尝试调用 Socket.reconnect() 方法,但它不起作用,也没有建立连接。有任何想法或替代解决方案吗?

如果有人遇到与 Socket.io 相同的问题,我设法解决这个问题的方法 API:

首先,您应该将 Socket 封装到构造函数创建的对象中,但是不需要创建重新连接方法,因为连接已经存在(并且可以通过发出的事件处理身份验证,我将在下面描述) :

import io from 'socket.io-client';
import { remoteUrl } from './constants/RemoteUrl';
import SocketWorker from './utilities/SocketWorker';

function Socket() {
  this.socket = io.connect(remoteUrl + '?role=user');

  this.socket.on('statusChange', (data) => {
    return SocketWorker.receiveOrderStatusChange(data);
  })
};

const socket = new Socket();

export  { socket };

您可以在项目中的任何位置导入套接字:

import {socket} from './Socket';

您可以拨打:

socket.socket.emit('joinRoleRoom','user');
socket.socket.emit('joinIdRoom', _user._id);

在服务器端,您只需要按如下方式处理这些事件:

socket.on('joinRoleRoom', (role) => {
  socket.join(role)
  console.log('Client joined to: ' + role);
});
socket.on('joinIdRoom', (id) => {
  console.log('Client joined to: ' + id);
  socket.join(id)
});

socket会根据认证过程中获得的认证信息加入必要的房间。

sznrbrt 最初接受的答案可以工作,但要注意它有一个严重的安全漏洞。

如果您执行以下操作,攻击者只需传递所需 user_id 即可加入房间并开始接收敏感的用户信息。可能是两个人之间的私信。

socket.socket.emit('joinRoleRoom','user');
socket.socket.emit('joinIdRoom', user_id);

Socket.io 有一个选项可以通过 extraHeaders。可以使用它来传递来自客户端的令牌。服务器将使用所需的身份验证算法来解密令牌并获得 user_id.

示例: socket.js

import io from 'socket.io-client';
import { remoteUrl } from './constants/RemoteUrl';
import SocketWorker from './utilities/SocketWorker';

const socket = io.connect(remoteUrl + '?role=user');

const socketAuth = () => {
  socket.io.opts.extraHeaders = {
    'x-auth-token': 'SET_TOKEN',
  };
  socket.io.opts.transportOptions = {
    polling: {
      extraHeaders: {
        'x-auth-token': 'SET_TOKEN',
      },
    },
  };
  socket.io.disconnect();
  socket.io.open(); 
};

export  { socket, socketAuth };

client.js

import { socket, socketAuth } from './socket';  

//After user logs in 
socketAuth();

server.js,使用包socketio-jwt-auth

io.use(jwtAuth.authenticate({
  secret: 'SECRET',
  succeedWithoutToken: true
}, (payload, done) => {
  if (payload && payload.id) {
    return done(null, payload.id);
  }
  return done();
}));