【问题标题】:Send SocketIO message on unload or upon confirmation onbeforeunload在卸载或确认 onbeforeunload 时发送 SocketIO 消息
【发布时间】:2018-08-17 11:12:47
【问题描述】:

我有一个服务器应用程序,它通过无线电在远程设备上执行固件更新。

有时更新可能会一直持续下去(如果无线电网络出现干扰)。在这种情况下,用户可能希望通过刷新或离开页面来中断更新。在这种情况下,我必须:

  1. 提醒用户他即将中断更新(不推荐),如果用户确定他的决定(并确认):

  2. 向服务器发送一个socketIO事件,通知应该取消更新。

我通过互联网搜索并找到了不同的解决方案。其中最好的是将处理程序分配给全局对象事件onbeforeunloadonunload

  • 使用onbeforeunload 我别无选择。只有在用户确认后才能发送 SocketIO 消息,如果用户决定等待更新完成,则什么也不做。我可以将 SocketIO 消息发送到服务器,但是如果用户决定等待呢?伤害已经造成。

  • 使用onunload - 似乎对我不起作用。我看到浏览器正在发送套接字事件,但在服务器处理之前,连接已关闭。

有没有办法保持 SocketIO 连接或延迟浏览器刷新,以便服务器可以处理事件。

我认为这是服务器的问题,因为它在 CPU 上运行,资源非常有限,甚至 CPU 速度也是如此。是ARM A7架构。

【问题讨论】:

    标签: javascript node.js socket.io


    【解决方案1】:

    有办法:

    服务器:创建用户 ID:

    var custom_id = 0;
    io.engine.generateId = (req) => {
        let id = custom_id++;
        return id++; // very basic but unique id
      }
    

    服务器:创建尝试关闭事件的侦听器并存储用户ID尝试:

    var userAttempt = 0;
    
    socket.on('attempt to close', function(data){
      userAttempt = socket.id;
      console.log(data)
    })
    

    服务器:修改disconnect事件检查哪个id用户断开连接:

    socket.on('disconnect', function(){
        if(userAttempt === socket.id){
          console.log("user attempt and close");
         //the update should be canceled !!!!
        }
        console.log('user disconnected');
      });
    

    客户端:在onbeforeunload 内创建事件发射器尝试关闭,如果用户尝试关闭或重新加载页面,该事件总是会被触发。

    window.onbeforeunload = function (e) {
          e.returnValue = " ";
          var socket = io();
          socket.emit('attempt to close', "user attempt to close");
        };
    

    如果用户尝试关闭标签页,我们会触发 attempt to close 事件,我们会检查用户是否关闭标签页并检查 disconnect 事件。如果用户断开连接与用户尝试关闭相同,则应取消更新。

    【讨论】:

      【解决方案2】:

      我所做的是将套接字事件放入 window.addEventListener('unload', function (e) {});

          window.addEventListener('beforeunload', function (e) {
              e.preventDefault();
              e.returnValue = ' ';
          });
      
      
          window.addEventListener('unload', function (e) {
              socket.emit('some event', {data to be sent});
          });
      

      很好地完成了任务

      【讨论】:

        【解决方案3】:

        虽然这并不能完全回答问题,但以下是我使用 Chrome 版本 95.0.4638.54(官方构建)(64 位)和 socket.io 所做的一些观察。

        1. window.beforeunload 或 window.unload 事件会导致套接字在您通过 socket.io 发送窗口/选项卡正在关闭的消息之前断开连接。

        2. 最好在可以检测到断开连接的服务器上进行管理:(https://socket.io/docs/v4/server-api/)

          socket.on("断开连接", (原因) => {

           // reason = disconnect, server shutting down, ping timeout, 
           //transport close, transport error
           console.log('disconnect:'+reason+ ' '+socket.id);
          
          //then do your stuff
          

          });

          如果您在服务器上管理用户 ID 和套接字 ID 之间的连接,则可以跟踪谁在做什么等。我怀疑给出的答案可能在 3 年前有效,但 Chrome 发生了很大变化,我总是在我可以使用 socket.emit 之前断开了套接字。

          希望这会有所帮助。

        21 年 6 月 11 日更新 最新版本 (v4.1.0 =>) 默认将“closeOnBeforeunload”设置为 true 这将导致套接字在您发送消息之前关闭。 您当然可以将其设置为 false。

        (来自文档的引用): "在浏览器中发出 beforeunload 事件时是否(静默)关闭连接。

        当 closeOnBeforeunload 设置为 false 时,当用户在 Firefox 上(但不是在 Chrome 或 Safari 上)重新加载页面时,Socket 实例将发出断开连接事件。

        将 closeOnBeforeunload 设置为 true,所有浏览器将具有相同的行为(重新加载页面时没有断开连接事件)。但是,如果您在应用程序中使用 beforeunload 事件,这可能会导致问题。 "

        见:https://socket.io/docs/v4/client-options/#closeonbeforeunload

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2021-12-21
          • 2011-05-29
          • 1970-01-01
          • 2015-01-09
          • 1970-01-01
          • 2019-06-06
          • 2015-04-17
          • 1970-01-01
          相关资源
          最近更新 更多