长连接断了怎么办?手动重连不靠谱
你有没有遇到过这种情况:网页开着一个实时聊天窗口,突然消息不更新了,刷新页面才恢复。或者看直播时卡住,等半天也没自动恢复。这其实是长连接(比如 WebSocket)断开了,但程序没及时处理重连。
长连接和普通的 HTTP 请求不一样,它是一次建立、长期保持的通信通道。一旦网络波动、设备休眠、服务器重启,连接就可能中断。这时候靠用户刷新页面不是长久之计,得让程序自己“醒过来”重新连上。
检测断开是第一步
浏览器里的 WebSocket 对象本身不会主动告诉你“我已经断了”,尤其是网络层静默断开的时候。所以得自己想办法探测。常见的做法是定时发个心跳包:
const socket = new WebSocket('wss://example.com/live');
let heartBeatTimer;
socket.onopen = () => {
// 连接成功后启动心跳
heartBeatTimer = setInterval(() => {
if (socket.readyState === WebSocket.OPEN) {
socket.send('ping');
}
}, 30000); // 每30秒发一次
};
socket.onclose = () => {
clearInterval(heartBeatTimer);
console.log('连接已关闭,准备重试');
reconnect();
};
socket.onerror = (err) => {
console.error('连接出错', err);
socket.close(); // 主动关闭触发重连
};自动重连别太急
一断就立刻重试,万一网络还没恢复,反而加重负担。更稳妥的方式是加个延迟,并逐步延长间隔时间,避免频繁无效尝试:
let reconnectTimeout = 1000; // 初始1秒后重试
let maxReconnectDelay = 30000; // 最大重连间隔30秒
let reconnectAttempts = 0;
function reconnect() {
setTimeout(() => {
console.log(`第${++reconnectAttempts}次尝试重连`);
const newSocket = new WebSocket('wss://example.com/live');
setupSocket(newSocket); // 绑定事件
}, reconnectTimeout);
// 指数退避,最多到30秒
reconnectTimeout = Math.min(reconnectTimeout * 2, maxReconnectDelay);
}
function setupSocket(socket) {
socket.onopen = () => {
console.log('重连成功');
reconnectTimeout = 1000; // 成功后重置间隔
reconnectAttempts = 0;
};
socket.onclose = () => {
reconnect();
};
socket.onerror = () => {
socket.close();
};
}这样即使连续失败,也不会疯狂请求。比如第一次1秒后重试,第二次2秒,第四次8秒,慢慢来,等网络恢复。
页面切出去再回来,也得续上
手机上切到别的 App 一会儿,浏览器可能暂停 JavaScript,心跳停了,回来时连接早断了。可以监听页面可见性变化,回来时主动检查状态:
document.addEventListener('visibilitychange', () => {
if (!document.hidden && socket && socket.readyState !== WebSocket.OPEN) {
console.log('页面回到前台,检查连接状态');
reconnect();
}
});配合心跳机制,能覆盖大部分常见断连场景。
别忘了给用户一点提示
虽然程序在后台努力重连,但用户看到的可能是“消息不动了”。加个小提示,比如顶部显示“正在重连...”,成功后再消失,体验会好很多。别让用户干等。