【问题标题】:Socket.io disconnect on React client is not triggered on page refresh页面刷新时不会触发 React 客户端上的 Socket.io 断开连接
【发布时间】:2021-01-28 06:08:26
【问题描述】:

我有 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
    };
}

服务器端:

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;

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

服务器端日志:

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

对于如何正确处理客户端断开连接并重新初始化连接,我将不胜感激。

更新:

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

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

【问题讨论】:

    标签: node.js reactjs sockets websocket socket.io


    【解决方案1】:

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

    socket.on('disconnect', () => {
                console.log('Disconnected');
                onDisconnect();
            });
    

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

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

    这确实适用于页面重新加载,现在如果用户断开连接,说他们断开了互联网或类似的东西,这就是 socket.io beforeReconnect 和 reconnect 进来的地方,它会继续尝试 ping 服务器尝试并重新连接。在这种情况下,您可以将客户代码重新连接,但同样,如果他们正在重新加载页面,它应该可以工作。

    【讨论】:

    • 感谢您的解释。我没有意识到这一点,我发现了一些在客户端也实现了断开连接的示例/讨论,但是您的解释现在是有道理的。我想请您对服务器端的断开连接事件进行一些额外的说明。请在我原来的问题中检查“服务器端日志:”。我一直都在看到这种情况,如果这是表示重新连接的正常行为,或者这是同一客户端的多个连接的不良设计的危险信号,我应该如何验证它是否正常工作,我对此感到困惑。
    【解决方案2】:

    您可以使用如下代码确保只连接和断开一次:

    useEffect(() => {
        const socketService = new SocketService();
    
        console.log('mount it!');
        
        return function cleanup() {
            socketService.disconnect();
        }
    }, []);
    

    在这种情况下,SocketService 是一个简单的类,可以方便地使用套接字:

    import {io} from "socket.io-client";
    
    
    const ENDPOINT = 'ws://localhost:5000/';
    
    export default class SocketService {
        private socket: any = {};
    
        constructor(private emisor_id?: string) {
            this.socket = io(ENDPOINT);
        }
    
        public send = (message: string) => {
            this.socket.emit('postMessage', message)
        }
    
        // disconnect - used when unmounting
        public disconnect (): void {
            this.socket.disconnect();
        }
    }
    

    在服务器端,您应该会看到如下内容:

    connection
    client disconnected
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-07-17
      • 1970-01-01
      • 1970-01-01
      • 2017-06-19
      • 1970-01-01
      • 2017-03-21
      • 1970-01-01
      相关资源
      最近更新 更多