我有一个简单的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/