javascript - 防止 Socket IO 在 Chrome、firefox 和 Safari 移动浏览器上的非事件或不集中浏览器页面上 ping 超时

标签 javascript node.js google-chrome socket.io settimeout

我有一个简单的chat使用套接字 io 的应用程序。非常类似于socket io chat官方demo。每当用户最小化页面或打开另一个应用程序或页面失去焦点时,Socket io 在所有移动浏览器上都会出现 ping 超时。

在我的网络应用程序中,每当用户从移动设备上的 chrome/firefox/safari 浏览器单击文件输入上传时,它会打开手机对话框以从厨房中选择文件以进行选择和上传。在此期间(由于可见性,我的聊天页面失去焦点),当用户搜索文件时,恰好 30 秒后,socket io 客户端发出 ping 超时,并且人员聊天断开连接。

在我的应用程序级别,如果套接字 io 出于某种原因进入 ping 超时,我正在重新连接,但这并不能解决我的问题,因为如果用户在 31 秒后单击 1 个文件,则不会发送该图像文件聊天,因为在那段时间套接字 io 超时,当用户的焦点回到浏览器选项卡上时,重新连接需要几秒钟。因此文件上传操作丢失,因为文件已上传但套接字 io 连接在 ping 超时。因此,当它重新连接时,所选文件上传永远不会发送给其他连接的用户。

我尝试使用此代码检测用户的页面焦点何时消失,

document.addEventListener("visibilitychange", onchange);

来自 Is there a way to detect if a browser window is not currently active?

然后一旦页面不在焦点上,我使用 setinterval 将我的自定义心跳事件发送到我的服务器代码。 (只是为了防止套接字 io 与服务器通信以保持连接处于事件状态).. 这适用于桌面浏览器,但在所有移动浏览器上,只要用户的页面不在焦点上,即如果用户最小化浏览器,就会打开一个新应用程序,或转到选择文件上传屏幕,socket io 在 30 秒后超时,有时甚至更快。

我的客户端js代码:
var beating;
//function to detect if user gone out of page

//startSimulation and pauseSimulation defined elsewhere
function handleVisibilityChange() {
  //socket = this.socket;
  if (document.hidden) {
    // console.log();
    $('#logwrapper').prepend(" üser is outside \n ", socket.id);

    //emit on server after every 10 seconds
    beating = setInterval(function () {
      $('#logwrapper').prepend(" inside interval emitting");

      socket.emit('heartbeat', { data: "a" });
    }, 15000)

  } else {
    //console.log("üser is in");
    $('#logwrapper').prepend(" üser is in \n ", socket.id);
    console.log("çlearing inteval beating from visiblity");
    clearInterval(beating);
  }
}

document.addEventListener("visibilitychange", handleVisibilityChange, false);

还有我的 server.js 代码

  //socket events for heartbeat 
    socket.on("heartbeat", function (data) {
      console.log("socket is outside ", data, socket.id);
    });
    //socket events for heartbeat , just log it so that my client remains active and keep communicating with server, to avoid socket io timeout


我还尝试调整我的套接字 io 服务器和客户端超时配置,但这没有任何区别,在用户最小化移动设备、chorme、firefox 和 safari 上的浏览​​器页面后,套接字 io 客户端在 30 秒左右后发出 ping 超时,

如何增加此超时,以便套接字 io 连接保持事件状态(不要 ping 超时)更长的时间(如我所愿)?

这是我的 socket io 的 server.js 配置:

var io = require("socket.io")(
  231, {
    transports: ["websocket", "polling"]
  },
  server, {
    path: '/socket.io',
    serveClient: true,
    // below are engine.IO options
    pingInterval: 25000, //was 10k, how many ms before sending a new ping packet, => how often to send a ping
    pingTimeout: 30000, //should be above 30k to fix disconnection issue how many ms without a pong packet to consider the connection closed
    upgradeTimeout: 20000, // default value is 10000ms, try changing it to 20k or more
    agent: false,
    cookie: false,
    rejectUnauthorized: false,
    reconnectionDelay: 1000,
    reconnectionDelayMax: 5000,
    maxHttpBufferSize: 100000000 //100 mb
  }
);

和我的套接字 io 客户端配置:

 this.socket = io.connect('https://appurl.com', {
      reconnection: true,
      reconnectionDelay: 1000,
      reconnectionDelayMax: 5000,
      reconnectionAttempts: Infinity,
      //our site options
      transports: ["polling", "websocket"],
      secure: true,
      rejectUnauthorized: false,
      forceNew: false,
      timeout: 60000
    });

基本上在所有移动浏览器上,只要页面失去焦点,我的 JS 代码就会停止执行,并且每当页面再次聚焦时,JS 执行就会恢复,看起来它不是 setinterval 或 settimeout 的问题。如何继续执行我的客户端 JS 代码以防止套接字 io 执行 ping 超时?

我还使用 settimeout 尝试了类似的逻辑,https://codepen.io/Suhoij/pen/jAxtn

此代码适用于所有移动浏览器上的 codepen,即使我在移动设备上最小化此页面并再次返回,计时器仍在执行,但当我在我的应用程序上运行相同的代码时,它在我的代码中不起作用。为什么?当页面不在焦点时,socket io 是否会暂停我的所有 client.js 代码?或者我的逻辑不正确?我还尝试在每 2 秒后从我的 server.js 向所有客户端发出一个事件,但是当页面不在移动设备上时发出停止:/

相关套接字 io 问题:
https://github.com/socketio/socket.io/issues/2769

最佳答案

对于我必须在 socket.io 4.4.1 上做的事情
我使用管理器事件来处理移动设备上的断开连接
https://socket.io/docs/v4/client-api/#event-error

    import io from "socket.io-client";
    socket = io(socketUrl, {
        reconnectionAttempts,
        reconnectionDelay,
    });

    //for the actual websocket having an error attempt to reconnect
    socket.io.on("error", (error) => {
        // ...
        console.log('socket io error on ' + error);
        socket = io(socketUrl, {
            reconnectionAttempts,
            reconnectionDelay,
        });
    });

    let socketArray = ['reconnect', 'reconnect_attempt', 'reconnect_error', 'reconnect_failed'];

    for(let i = 0, len = socketArray.length; i < len; i++) {
        socket.io.on(socketArray[i], (attempt) => {
            // ...
            console.log(socketArray[i] + ' socket io on ' + attempt);
        });
    }
这使得如果 websocket 管理器出现错误,它将重新连接。当我在套接字上的浏览器中时发生了这种情况,关闭我的 iPhone,回到使用 socket.on('connection' 重新连接的浏览器很好,然后当我再次关闭手机屏幕然后重新进入时,我会收到此错误 WebSocket connection to 'wss://mysocketserver.com' failed: The operation couldn’t be completed. (kNWErrorDomainPOSIX error 53 - Software caused connection abort)通过添加 socket.io.on("error"并让它重新连接它会正确地重新建立每一件事

关于javascript - 防止 Socket IO 在 Chrome、firefox 和 Safari 移动浏览器上的非事件或不集中浏览器页面上 ping 超时,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58667207/

相关文章:

javascript - Node.js - 在使用 Express 时未定义端口时停止应用程序

css - 我如何在我的用户样式表中选择跨域链接?

css - Chrome 和 IE9 没有将按钮上的文本居中

node.js - 我需要使用 nginx 服务器为 node.js 项目设置我的域

html - 在 Chrome 中聚焦时,部分隐藏的按钮会跳起来

javascript - 如何用单词替换 JavaScript 中的最后一个字符?

javascript - mapbox - 如何设置要素图层的弹出选项

javascript - 使用粘性 div 平滑滚动

javascript - 如何使用 NodeJS 从 MongoDb 获取 JSONObject 形式的结果