1. WebSocket 基础
-
定义:HTML5 提供的全双工通信协议,允许客户端和服务器实时双向数据传输。
-
特点:
- 基于 TCP,复用 HTTP 握手通道(通过
Upgrade头切换协议)。 - 持久化连接,避免 HTTP 短连接的频繁开销。
- 支持文本(String/JSON)和二进制数据传输。
- 基于 TCP,复用 HTTP 握手通道(通过
2. 与 HTTP 对比
| 特性 | HTTP | WebSocket |
|---|---|---|
| 连接方式 | 短连接(请求-响应) | 长连接(全双工) |
| 通信模式 | 单向(客户端发起) | 双向实时通信 |
| 头部开销 | 每次请求携带完整头部 | 初始握手后开销极小 |
| 适用场景 | 静态资源、REST API | 实时应用(聊天、游戏) |
3. 连接建立过程
-
握手阶段(HTTP Upgrade):
-
客户端发起请求:
GET /chat HTTP/1.1 Host: server.example.com Upgrade: websocket Connection: Upgrade Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== Sec-WebSocket-Version: 13 -
服务器响应(状态码 101):
HTTP/1.1 101 Switching Protocols Upgrade: websocket Connection: Upgrade Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
-
-
数据传输:通过帧(Frame)协议交换数据,支持分片传输。
心跳包实现详解
1. 为什么需要心跳包?
- 问题:网络不稳定可能导致连接假死(如防火墙静默丢弃连接)。
- 作用:定时检测连接活性,及时断开重连,避免数据卡死。
2. 实现步骤(客户端为例)
a. 心跳发送
let heartbeatInterval = 30000; // 30秒发送一次
let timeoutThreshold = 3; // 允许连续3次无响应
let missedPongs = 0;
let heartbeatTimer;
// 连接建立后启动心跳
websocket.onopen = () => {
startHeartbeat();
};
function startHeartbeat() {
heartbeatTimer = setInterval(() => {
if (missedPongs >= timeoutThreshold) {
reconnect();
return;
}
websocket.send(JSON.stringify({ type: 'ping' }));
missedPongs++;
}, heartbeatInterval);
}
b. 心跳应答处理
websocket.onmessage = (event) => {
const data = JSON.parse(event.data);
if (data.type === 'pong') {
missedPongs = 0; // 重置未应答计数
}
};
c. 异常处理与重连
function reconnect() {
clearInterval(heartbeatTimer);
websocket.close();
// 使用指数退避策略重连
setTimeout(() => {
new WebSocket(url);
}, Math.min(1000 * Math.pow(2, retryCount), 30000));
}
websocket.onclose = () => {
clearInterval(heartbeatTimer);
};
3. 服务端配合
- 响应心跳:收到
ping后立即回复pong。 - 活性检测:定时检查客户端最后活动时间,超时主动断开。
最佳实践与注意事项
-
心跳间隔选择:根据场景调整(如 30秒-60秒),平衡及时性与性能。
-
安全加固:
- 使用
wss://防止中间人攻击。 - 验证
Origin头防止跨站劫持。
- 使用
-
错误处理:
- 监听
onerror事件记录日志。 - 重连时增加延迟,避免暴力重试(指数退避)。
- 监听
-
性能优化:心跳包尽量轻量(如
{type:'ping'})。
应用场景示例
- 即时通讯(如微信网页版)
- 实时数据监控(股票行情、物流追踪)
- 多人在线游戏(状态同步)
- 协同编辑工具(如 Google Docs)