You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS 15 Safari页面失焦时WebSocket连接随机断开问题

iOS 15 Safari WebSocket 假在线问题解决办法

这个问题是iOS 15 Safari的后台资源限制导致的——浏览器会在页面失焦后静默挂起WebSocket连接,但不会触发close事件,也不更新readyState,导致客户端误以为连接还是正常的,但实际已经无法收发消息。

解决思路及实现

1. 强制心跳检测

不要依赖readyState判断连接状态,通过定时发送ping帧+服务器返回pong的方式,主动验证连接有效性:

let ws;
let heartbeatTimer;
let pingTimeout;

// 创建WebSocket连接
function initWS() {
  ws = new WebSocket('ws://your-server-address');
  
  ws.onopen = () => {
    startHeartbeat();
  };

  ws.onmessage = (e) => {
    // 收到服务器的pong响应,重置超时器
    if (e.data === 'pong') {
      clearTimeout(pingTimeout);
    }
    // 处理业务消息
  };

  ws.onclose = () => {
    stopHeartbeat();
    // 断开后自动重连
    setTimeout(initWS, 3000);
  };
}

// 启动心跳
function startHeartbeat() {
  // 每10秒发送一次ping(间隔不宜过短,避免被iOS后台节流)
  heartbeatTimer = setInterval(() => {
    if (ws.readyState === WebSocket.OPEN) {
      ws.send('ping');
      // 5秒内没收到pong,判定连接失效
      pingTimeout = setTimeout(() => {
        ws.close();
      }, 5000);
    }
  }, 10000);
}

// 停止心跳
function stopHeartbeat() {
  clearInterval(heartbeatTimer);
  clearTimeout(pingTimeout);
}

2. 页面切前台主动校验

利用页面可见性API,在用户切回页面时主动触发一次连接校验:

document.addEventListener('visibilitychange', () => {
  if (document.visibilityState === 'visible') {
    if (ws && ws.readyState === WebSocket.OPEN) {
      // 主动发ping,验证连接是否真的存活
      ws.send('ping');
      pingTimeout = setTimeout(() => {
        ws.close();
      }, 5000);
    } else {
      initWS();
    }
  }
});

3. 服务器端配合

确保服务器收到ping消息后立即返回pong响应,这样客户端才能准确判断连接状态。

注意事项

  • iOS 15 Safari后台会大幅降低定时器频率,心跳间隔建议设为10秒以上,避免定时器被节流导致心跳失效。
  • 不要仅通过ws.readyState === OPEN判断连接有效性,必须结合心跳响应结果。

内容的提问来源于stack exchange,提问作者Tao Li

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 19:11:31