WebSocket心跳检测如何避免频繁断开?
在开发实时聊天功能时,我给WebSocket加了心跳检测,但每隔10分钟还是会被断开。已经用setInterval()每30秒发送心跳,服务端超时设置是35秒,这是哪里出了问题?
代码是这样的:
let ws = new WebSocket('wss://api.example.com');
ws.addEventListener('open', () => {
setInterval(() => {
if (ws.readyState === 1) ws.send('heartbeat');
}, 30000);
});
测试时发现,如果用户手机锁屏超过5分钟,重新点亮后就会触发连接断开。难道是移动端网络状态变化导致心跳包没发出?试过把间隔缩短到15秒但服务器说频次太高,这个怎么平衡啊?
得加个页面可见性监听,检测用户是否在前台。不在前台的时候别傻等定时器,等回来再重连。可以这样改:
另外跟后端确认下是不是代理层(比如Nginx)有60秒读超时限制,有时候不是你的锅。建议心跳包用 ping 帧(opcode=9)而不是文本消息,更标准也更轻量。如果服务端支持,优先用 WebSocket 内建的 ping/pong 机制。
关键不是调得更频繁,而是要加两个东西:一个是心跳失败重试,另一个是网络状态监听。你可以改成这样:
另外提醒一点,有些服务器会限制连续心跳包频率,你可以把客户端设成30秒一次,只要保证“一个心跳周期内至少成功发出一次”就行。重点是加上重连机制和网络监听,别指望setInterval在后台一直跑。
我之前测试的时候发现iOS微信里锁屏几分钟,setInterval直接卡住不执行,等亮屏才一股脑补回来,这时候虽然时间看起来没超,但实际已经断了。所以必须靠readyState判断+自动重连兜底。