为什么 1 分钟就会断开?
在客户端和服务器之间,往往存在 Nginx、云厂商的负载均衡器(如 AWS ALB)等反向代理。它们都有一个“空闲超时时间(Idle Timeout)”的默认设置。如果在这段时间内没有数据交互,代理就会强制断开 TCP 连接。
- 常见默认值:Nginx、AWS ALB、Azure 等通常默认就是 60秒。这就是你遇到“刚好 1 分钟断开”的根本原因。
解决方案:添加心跳机制
心跳机制的原理非常简单:客户端和服务器每隔一小段时间(比如 30 秒),互相发送一个极小的数据包(通常叫 ping 和 pong)。这就像两个人打电话时偶尔“喂”一声,告诉对方“我还在线,别挂电话”。
1. 前端客户端实现(JavaScript)
由于浏览器的 WebSocket API 无法直接操作底层的协议级 ping/pong,我们需要在应用层自己实现。通常建议每 30 秒发送一次心跳(小于 60 秒的超时阈值)。
class WebSocketManager {
constructor(url) {
this.url = url;
this.ws = null;
this.heartbeatTimer = null;
this.heartbeatInterval = 30000; // 30秒发送一次心跳
}
connect() {
this.ws = new WebSocket(this.url);
this.ws.onopen = () => {
console.log('WebSocket 连接成功');
this.startHeartbeat(); // 连接成功后开启心跳
};
this.ws.onmessage = (event) => {
const data = JSON.parse(event.data);
// 收到服务器的 pong 响应,说明连接健康
if (data.type === 'pong') {
console.log('收到心跳响应,连接正常');
return;
}
// 处理其他业务消息...
};
this.ws.onclose = () => {
console.log('连接已断开');
this.stopHeartbeat(); // 断开后停止心跳,防止内存泄漏
};
}
// 开启心跳
startHeartbeat() {
this.stopHeartbeat(); // 先清除可能存在的旧定时器
this.heartbeatTimer = setInterval(() => {
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
// 发送心跳包
this.ws.send(JSON.stringify({ type: 'ping' }));
}
}, this.heartbeatInterval);
}
// 停止心跳
stopHeartbeat() {
if (this.heartbeatTimer) {
clearInterval(this.heartbeatTimer);
this.heartbeatTimer = null;
}
}
}
2. 后端服务器响应
服务器端在接收到 type: 'ping' 的消息后,需要立即回复一个 type: 'pong' 的消息。以 Node.js 为例:
ws.on('message', (message) => {
const data = JSON.parse(message);
if (data.type === 'ping') {
// 收到心跳,立即回复 pong
ws.send(JSON.stringify({ type: 'pong' }));
}
// 处理其他业务逻辑...
});
(注:如果你使用的是 Spring Boot 等框架,也可以通过配置 STOMP 协议的 setHeartbeatValue 来实现标准的心跳机制。)
⚙️ 配套优化:检查 Nginx 配置
除了前端加心跳,如果你能控制服务器,强烈建议检查并修改 Nginx 的超时配置。将 proxy_read_timeout 和 proxy_send_timeout 设置得比心跳间隔更长(例如 75 秒):
location /ws-endpoint {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
# 将超时时间延长至 75 秒,给心跳留出足够的缓冲时间
proxy_read_timeout 75s;
proxy_send_timeout 75s;
}
总结建议:保留 WebSocket 长连接,在前端加入 30 秒间隔的应用层心跳机制,并确保后端能响应 pong。这套组合拳能完美解决 1 分钟断连的问题,同时保持实时通信的高性能。