一、为什么需要WebSocket?
想象一下这样的场景:你在网页上聊天,每发一条消息都要手动刷新页面才能看到回复——这简直像回到了2005年。传统的HTTP协议就像写信,发一次请求等一次回复,而WebSocket则是打电话,建立连接后双方随时可以交流。
核心优势:
- 双向通信:服务器可以主动推数据给前端(比如股票行情实时更新)
- 低延迟:省去了反复建立连接的耗时(HTTP的3次握手再见啦)
- 轻量级:数据头只有2-10字节,比HTTP headers小得多
// 技术栈:JavaScript + WebSocket API
// 示例1:建立基础连接
const socket = new WebSocket('wss://your-websocket-server.com');
// 监听连接成功事件
socket.addEventListener('open', (event) => {
console.log('连接已建立,可以开始聊天了!');
socket.send('你好服务器,我是客户端A'); // 发送第一条消息
});
// 监听服务器消息
socket.addEventListener('message', (event) => {
console.log('收到服务器消息:', event.data);
});
二、如何正确建立和维持连接?
WebSocket用起来简单,但要稳定运行得像老黄牛,得注意这些细节:
1. 连接保活
网络不稳定时自动重连是基本操作:
// 示例2:自动重连机制
let socket;
const maxRetry = 5; // 最大重试次数
function connect() {
socket = new WebSocket('wss://your-server.com');
socket.onclose = () => {
console.log('连接断开,3秒后重试...');
if (maxRetry-- > 0) setTimeout(connect, 3000);
};
}
connect(); // 初始连接
2. 心跳检测
防止连接假死,定期发个"心跳包":
// 示例3:心跳检测
setInterval(() => {
if (socket.readyState === WebSocket.OPEN) {
socket.send(JSON.stringify({ type: 'heartbeat' }));
}
}, 30000); // 每30秒一次
三、数据格式的优雅处理
直接发字符串太原始,推荐两种结构化方案:
方案A:JSON包装
适合大多数业务场景
// 示例4:结构化消息协议
function sendMessage(type, payload) {
socket.send(JSON.stringify({
type, // 消息类型:chat/notification/alert
timestamp: Date.now(),
data: payload
}));
}
// 使用示例
sendMessage('chat', { text: '今晚吃啥?', userId: 123 });
方案B:二进制数据
适合传输文件或音视频流
// 示例5:发送二进制数据
const fileInput = document.getElementById('file-upload');
fileInput.addEventListener('change', (e) => {
const file = e.target.files[0];
const reader = new FileReader();
reader.onload = (event) => {
socket.send(event.target.result); // 直接发送ArrayBuffer
};
reader.readAsArrayBuffer(file);
});
四、必须知道的性能优化技巧
1. 消息合并
高频场景下(如实时股价),别一条条发:
// 示例6:批量消息处理
let messageQueue = [];
const BATCH_INTERVAL = 100; // 每100ms批量发送一次
setInterval(() => {
if (messageQueue.length > 0) {
socket.send(JSON.stringify(messageQueue));
messageQueue = [];
}
}, BATCH_INTERVAL);
// 业务代码调用
function pushToQueue(msg) {
messageQueue.push(msg);
}
2. 连接共享
多个功能复用同个连接:
// 示例7:多频道复用连接
function subscribe(channel) {
socket.send(JSON.stringify({
action: 'subscribe',
channel: channel // 如:news/weather/stocks
}));
}
// 同时接收新闻和天气
subscribe('news');
subscribe('weather');
五、典型业务场景实战
场景1:在线协作编辑
多人同时编辑文档时,用WebSocket同步内容:
// 示例8:协同编辑实现
document.getElementById('editor').addEventListener('input', (e) => {
const changes = {
position: e.target.selectionStart,
text: e.target.value
};
socket.send(JSON.stringify({
type: 'document_edit',
changes
}));
});
场景2:实时游戏状态同步
玩家移动位置时立即广播给其他玩家:
// 示例9:游戏状态同步
player.onMove((x, y) => {
socket.send(JSON.stringify({
type: 'player_move',
x,
y,
playerId: 'player_123'
}));
});
六、避坑指南
1. 注意连接状态
发送前务必检查:
// 示例10:安全发送消息
function safeSend(data) {
if (socket.readyState !== WebSocket.OPEN) {
console.error('连接未就绪');
return false;
}
socket.send(data);
return true;
}
2. 控制消息体积
大消息分片发送:
// 示例11:大文件分片传输
const CHUNK_SIZE = 1024 * 16; // 16KB每片
function sendLargeFile(file) {
const chunkCount = Math.ceil(file.size / CHUNK_SIZE);
for (let i = 0; i < chunkCount; i++) {
const chunk = file.slice(i * CHUNK_SIZE, (i + 1) * CHUNK_SIZE);
socket.send(chunk);
}
}
七、技术选型对比
| 方案 | 优点 | 缺点 |
|---|---|---|
| 原生WebSocket | 浏览器内置,零依赖 | 缺乏高级功能如自动重连 |
| Socket.IO | 断线重连/多路复用 | 体积较大(100KB+) |
| WS | Node.js后端首选 | 需要自行处理跨域 |
八、安全防护要点
- 必须使用wss协议(WebSocket over TLS)
- 验证消息来源:
// 示例12:消息来源验证
socket.addEventListener('message', (event) => {
try {
const msg = JSON.parse(event.data);
if (msg.token !== '预共享密钥') {
throw new Error('非法消息');
}
// 处理合法消息...
} catch (e) {
console.error('消息验证失败', e);
}
});
九、未来演进方向
- HTTP/3支持:基于QUIC协议提升弱网表现
- WebTransport:下一代多路传输协议(Chrome已实验性支持)
// 示例13:未来可能这样写
const transport = new WebTransport('https://example.com');
const stream = await transport.createBidirectionalStream();
十、总结与决策建议
适合WebSocket的场景:
- 需要服务器主动推送(聊天室、实时监控)
- 高频双向交互(在线游戏、协同编辑)
不建议使用的场景:
- 简单数据查询(用HTTP够用)
- 超低频通知(用轮询或SSE更简单)
记住:技术没有银弹,选对工具比会用工具更重要!
评论