WebSocket作为前端实现实时双向通信的常用技术,在即时通讯、实时数据推送等场景中应用广泛,但长连接受网络环境、服务端配置等因素影响容易出现断开情况,因此需要配合心跳机制维持连接活性。下面介绍三种常见的JS操作WebSocket心跳的实现方式。

一、定时发送心跳包机制
这种机制的核心逻辑是客户端每隔固定时间向服务端发送一个约定的心跳消息,服务端收到后返回对应的响应,双方通过这种交互确认连接正常。如果发送心跳后长时间没有收到响应,就判定连接异常触发重连。
实现步骤如下:
- 建立WebSocket连接后启动定时心跳任务
- 心跳间隔内发送约定格式的心跳消息
- 收到服务端心跳响应后重置超时检测
- 心跳发送失败或超时未收到响应则关闭连接并重连
完整代码示例如下:
// 定义WebSocket实例和心跳相关变量
let ws = null;
let heartbeatTimer = null;
let heartbeatTimeout = null;
const HEARTBEAT_INTERVAL = 30000; // 心跳间隔30秒
const HEARTBEAT_TIMEOUT = 5000; // 心跳响应超时时间5秒
// 初始化WebSocket连接
function initWebSocket() {
ws = new WebSocket('ws://127.0.0.1:8080/ws');
ws.onopen = function() {
console.log('WebSocket连接已建立');
startHeartbeat();
};
ws.onmessage = function(event) {
const data = JSON.parse(event.data);
// 判断是否为心跳响应
if (data.type === 'heartbeat_response') {
resetHeartbeatTimeout();
}
// 处理其他业务消息
};
ws.onclose = function() {
console.log('WebSocket连接已关闭,准备重连');
stopHeartbeat();
// 3秒后尝试重连
setTimeout(initWebSocket, 3000);
};
ws.onerror = function() {
console.log('WebSocket连接出错');
ws.close();
};
}
// 启动心跳任务
function startHeartbeat() {
// 先清除之前的心跳定时器
stopHeartbeat();
// 定时发送心跳
heartbeatTimer = setInterval(() => {
if (ws && ws.readyState === WebSocket.OPEN) {
// 发送心跳消息
ws.send(JSON.stringify({
type: 'heartbeat',
timestamp: Date.now()
}));
// 启动心跳响应超时检测
heartbeatTimeout = setTimeout(() => {
console.log('心跳响应超时,连接异常');
ws.close();
}, HEARTBEAT_TIMEOUT);
}
}, HEARTBEAT_INTERVAL);
}
// 重置心跳超时检测
function resetHeartbeatTimeout() {
if (heartbeatTimeout) {
clearTimeout(heartbeatTimeout);
heartbeatTimeout = null;
}
}
// 停止心跳任务
function stopHeartbeat() {
if (heartbeatTimer) {
clearInterval(heartbeatTimer);
heartbeatTimer = null;
}
if (heartbeatTimeout) {
clearTimeout(heartbeatTimeout);
heartbeatTimeout = null;
}
}
// 初始化连接
initWebSocket();
二、响应超时检测心跳机制
这种机制不主动定时发送心跳,而是记录最后一次收到服务端消息的时间,每隔一段时间检查该时间与当前时间的差值,如果超过设定的阈值就判定连接异常,触发心跳发送或者重连操作。适合服务端会主动推送消息的场景,减少不必要的心跳请求。
实现逻辑如下:
- 维护一个最后消息接收时间戳变量
- 每次收到任意服务端消息都更新该时间戳
- 启动定时检测任务,对比当前时间和最后接收时间的差值
- 差值超过阈值则发送心跳验证,验证失败则重连
代码示例如下:
let ws = null;
let checkTimer = null;
let lastMessageTime = 0;
const CHECK_INTERVAL = 10000; // 检测间隔10秒
const MAX_SILENCE_TIME = 40000; // 最大静默时间40秒
function initWebSocket() {
ws = new WebSocket('ws://127.0.0.1:8080/ws');
ws.onopen = function() {
console.log('连接建立');
lastMessageTime = Date.now();
startCheck();
};
ws.onmessage = function() {
// 收到任意消息都更新最后接收时间
lastMessageTime = Date.now();
// 处理业务逻辑
};
ws.onclose = function() {
console.log('连接关闭,准备重连');
stopCheck();
setTimeout(initWebSocket, 3000);
};
ws.onerror = function() {
ws.close();
};
}
// 启动检测任务
function startCheck() {
stopCheck();
checkTimer = setInterval(() => {
const now = Date.now();
const silenceTime = now - lastMessageTime;
if (silenceTime > MAX_SILENCE_TIME) {
console.log('长时间未收到消息,发送心跳验证');
// 发送心跳验证连接
if (ws && ws.readyState === WebSocket.OPEN) {
ws.send(JSON.stringify({
type: 'check_heartbeat'
}));
// 发送后1秒再检查一次,如果还没更新时间就重连
setTimeout(() => {
if (Date.now() - lastMessageTime > MAX_SILENCE_TIME) {
console.log('心跳验证失败,关闭连接');
ws.close();
}
}, 1000);
}
}
}, CHECK_INTERVAL);
}
// 停止检测任务
function stopCheck() {
if (checkTimer) {
clearInterval(checkTimer);
checkTimer = null;
}
}
initWebSocket();
三、状态轮询心跳机制
这种机制结合了连接状态检测和心跳发送,会同时维护连接状态和心跳任务,不仅检测心跳响应,还会主动检查WebSocket的readyState属性,适合对连接稳定性要求较高的场景,能够更及时地发现连接异常。
实现要点:
- 同时维护心跳发送定时器和状态检查定时器
- 心跳发送后记录发送时间,状态检查时同时验证连接状态和心跳响应情况
- 两种检测任意一种触发异常都执行重连逻辑
代码示例如下:
let ws = null;
let sendTimer = null;
let stateTimer = null;
let lastHeartbeatSendTime = 0;
const SEND_INTERVAL = 25000; // 心跳发送间隔25秒
const STATE_CHECK_INTERVAL = 5000; // 状态检查间隔5秒
const HEARTBEAT_VALID_TIME = 10000; // 心跳有效时间10秒
function initWebSocket() {
ws = new WebSocket('ws://127.0.0.1:8080/ws');
ws.onopen = function() {
console.log('连接成功');
startAllTask();
};
ws.onmessage = function(event) {
const data = JSON.parse(event.data);
if (data.type === 'heartbeat_ack') {
lastHeartbeatSendTime = 0; // 收到确认后重置发送时间
}
};
ws.onclose = function() {
console.log('连接断开,开始重连');
stopAllTask();
setTimeout(initWebSocket, 3000);
};
ws.onerror = function() {
ws.close();
};
}
// 启动所有任务
function startAllTask() {
// 心跳发送任务
sendTimer = setInterval(() => {
if (ws && ws.readyState === WebSocket.OPEN) {
ws.send(JSON.stringify({
type: 'heartbeat',
time: Date.now()
}));
lastHeartbeatSendTime = Date.now();
}
}, SEND_INTERVAL);
// 状态轮询任务
stateTimer = setInterval(() => {
// 检查连接状态
if (!ws || ws.readyState !== WebSocket.OPEN) {
console.log('连接状态异常,触发重连');
ws.close();
return;
}
// 检查心跳是否超时未响应
if (lastHeartbeatSendTime > 0 && (Date.now() - lastHeartbeatSendTime) > HEARTBEAT_VALID_TIME) {
console.log('心跳未收到确认,连接异常');
ws.close();
}
}, STATE_CHECK_INTERVAL);
}
// 停止所有任务
function stopAllTask() {
if (sendTimer) {
clearInterval(sendTimer);
sendTimer = null;
}
if (stateTimer) {
clearInterval(stateTimer);
stateTimer = null;
}
lastHeartbeatSendTime = 0;
}
initWebSocket();
三种机制对比
不同心跳机制的适用场景和特点如下表所示:
| 机制类型 | 实现复杂度 | 资源消耗 | 适用场景 |
|---|---|---|---|
| 定时发送心跳包 | 低 | 中 | 通用场景,服务端无主动推送的情况 |
| 响应超时检测 | 中 | 低 | 服务端会主动推送消息的场景 |
| 状态轮询心跳 | 高 | 中高 | 对连接稳定性要求高的核心业务场景 |
实际开发中可以根据业务的服务端特性、连接稳定性要求选择合适的机制,也可以将多种机制结合使用,进一步提升长连接的可靠性。