页面刷新时不会触发 React 客户端上的 Socket.io 断开连接

zor*_*mic 2 sockets websocket node.js socket.io reactjs

我有 React.js + Node.js 应用程序,我使用 Socket.io 通知 UI 端后端发生了一些更改,它应该拉取这些更改。我使用客户端 ID 作为套接字中的标识符,因此我不必在服务器端维护用户映射。

当用户登录时,我正在建立连接,并且此工作流程运行良好。当用户刷新页面时就会出现问题。在客户端套接字端的 Chrome 浏览器中,“断开连接”不会被触发,并且套接字不会重新连接。在 FF 中,第一次刷新时会触发断开连接,但客户端不会检索到 joinsuccess,并且客户端不会收到通知。在第二次和以后的每次刷新时,不会触发断开连接。

我的客户代码:

const io = require('socket.io-client');

export default function () {
    const socket = io.connect(process.env.REACT_APP_BACKEND_URL);

    function registerDisconnectHandler(onDisconnect) {
        socket.on('disconnect', () => {
            console.log('Disconnected');
            onDisconnect();
        });
    }
    function registerJoinHandler(onJoinSuccess) {
        socket.on('joinsuccess', (msg) => {
            console.log('join success');
            onJoinSuccess(msg);
        });
    }
    function joinNotification(channel, cb) {
        console.log(`emit join for channel:${JSON.stringify(channel)}`);
        socket.emit('joinnotificationpharmacy', channel, cb);
    }
    function registerNotificationHandler(onNotificationReceived) {
        socket.on('notification', (notification) => {
            onNotificationReceived(notification);
        });
    }
    socket.on('error', (err) => {
        console.log('received socket error:');
        console.log(err);
    });

    return {
        registerDisconnectHandler,
        registerNotificationHandler,
        registerJoinHandler,
        joinNotification
    };
}

Run Code Online (Sandbox Code Playgroud)

服务器端:

const socketIo = require('socket.io');

class SocketService {
    constructor(server) {
        this.io = socketIo(server);
        this.io.on('connect', socket => {
            socket.on('joinnotificationpharmacy', function(data){
                console.log('JOIN CLIENTID:'+data+" SOCKET ID:"+socket.id);
                socket.join(data);
                socket.emit('joinsuccess', socket.id);
            });
            socket.on('disconnect', function(){
                console.log("client has disconnected:"+socket.id);
            });
        });
        this.io.on('connect_error', function(err) {
            // handle server error here
            console.log('Error connecting to server');
        });
    }

    sendSocketNotification(receiver, notification){
        this.io.sockets.in(receiver).emit('notification', notification);
    }
}

module.exports = SocketService;

Run Code Online (Sandbox Code Playgroud)

服务器端的日志表明一个客户端加入了服务器,但是当刷新发生时,多个用户断开连接,这对我来说看起来很奇怪,看起来像是潜在的问题:

服务器端日志:

JOIN CLIENT:5f6cb94d1bb5adbab7866a14 ID:p9hC0OTKztwGlalWAAAa
client has disconnected:fJKV3MkJ4bxemZ4sAAAD
client has disconnected:xJ7bJvSqwXBbkxOhAAAI
client has disconnected:HkwouVqEXBeKvkHsAAAG
client has disconnected:9dd6e8huPveN8aVjAAAe
client has disconnected:jAZy4FXTC2oRd0a_AAAd
client has disconnected:Doonmd-ogmIRXU7iAAAc
client has disconnected:G-tc_RbO_99mivQyAAAb
client has disconnected:p9hC0OTKztwGlalWAAAa
client has disconnected:OYo2uOxuFzMeYtUEAAAW
client has disconnected:54HLS2-KHAWJ5NmqAAAR
client has disconnected:92veurywX4LhfK4cAAAg
client has disconnected:Ox73Zt-lMB0rFeA-AAAf
Run Code Online (Sandbox Code Playgroud)

我希望得到一些有关如何正确处理客户端断开连接并重新初始化连接的建议。

更新:

我已经找到了解决此问题的方法,但如果有人有更好的想法,仍然值得欢迎。我添加了一个代码,用于标识页面重新加载并更改 redux 状态,该状态用于标识该连接不再存在。

  useEffect(() => {
    if (sessionStorage.getItem('is_reloaded')) {
      console.log('Reloaded!');
      dispatch(disconnectNotificationsSocket(globalSocket, notifications.activeSocket));
    }
    sessionStorage.setItem('is_reloaded', true);
  }, []);
Run Code Online (Sandbox Code Playgroud)

pro*_*im0 6

只是指出一些事情(这里的文档可能会更好)

socket.on('disconnect', () => {
            console.log('Disconnected');
            onDisconnect();
        });
Run Code Online (Sandbox Code Playgroud)

不应该在客户端,这是在用户断开连接时为服务器保留的。

当您“重新加载”页面时,每次都会触发“断开连接”事件,这是默认行为。用于在客户端进行连接的脚本应该再次运行并重新加入套接字服务器,就像最初一样,尽管使用了不同的套接字。所以你真的不需要考虑太多,想想他们只是再次加入,而不是“重新加入”。

这实际上是针对页面重新加载的,现在如果用户断开连接,比如说他们断开了互联网或类似的事情,这就是 socket.io beforeReconnect 和 reconnect 发挥作用的地方,它将继续尝试 ping 服务器以尝试重新连接。在这种情况下,您可以放置​​客户代码来重新连接,但同样,如果他们重新加载页面,它应该可以工作。