1. 连接稳定性问题
心跳机制
TypeScript
复制代码
// 必须实现心跳保活
let heartbeatInterval;
const HEARTBEAT_INTERVAL = 30000; // 30秒
function setupHeartbeat(ws) {
heartbeatInterval = setInterval(() => {
if (ws.readyState === WebSocket.OPEN) {
ws.send(JSON.stringify({ type: 'ping' }));
}
}, HEARTBEAT_INTERVAL);
}
// 收到pong后重置超时计时器
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
if (data.type === 'pong') {
// 重置超时计时器
}
};
2. 重连机制
指数退避重连
TypeScript
复制代码
let reconnectAttempts = 0;
const MAX_RECONNECT_ATTEMPTS = 10;
const BASE_DELAY = 1000;
function reconnect() {
if (reconnectAttempts >= MAX_RECONNECT_ATTEMPTS) {
console.error('Max reconnection attempts reached');
return;
}
const delay = Math.min(BASE_DELAY * Math.pow(2, reconnectAttempts), 30000);
reconnectAttempts++;
setTimeout(() => {
initWebSocket();
}, delay);
}
ws.onclose = () => {
clearInterval(heartbeatInterval);
reconnect();
};
3. 消息顺序与并发控制
TypeScript
复制代码
// 消息队列处理
class WebSocketManager {
constructor() {
this.messageQueue = [];
this.isProcessing = false;
this.ws = null;
}
async sendMessage(message) {
this.messageQueue.push(message);
await this.processQueue();
}
async processQueue() {
if (this.isProcessing || !this.ws || this.ws.readyState !== WebSocket.OPEN) {
return;
}
this.isProcessing = true;
while (this.messageQueue.length > 0) {
const message = this.messageQueue.shift();
try {
await new Promise((resolve, reject) => {
this.ws.send(JSON.stringify(message));
// 等待服务器确认
const handler = (event) => {
const response = JSON.parse(event.data);
if (response.id === message.id) {
this.ws.removeEventListener('message', handler);
resolve();
}
};
this.ws.addEventListener('message', handler);
// 超时处理
setTimeout(() => {
this.ws.removeEventListener('message', handler);
reject(new Error('Timeout'));
}, 5000);
});
} catch (error) {
console.error('Send failed:', error);
this.messageQueue.unshift(message); // 重新放回队列
break;
}
}
this.isProcessing = false;
}
}
4. 二进制数据处理
TypeScript
复制代码
// 明确指定数据类型
ws.binaryType = 'arraybuffer'; // 或 'blob'
// 发送二进制数据
const buffer = new ArrayBuffer(32);
const view = new Uint8Array(buffer);
// ... 填充数据
ws.send(buffer);
// 接收二进制数据
ws.onmessage = (event) => {
if (event.data instanceof ArrayBuffer) {
const view = new Uint8Array(event.data);
// 处理二进制数据
} else {
// 处理文本数据
const text = event.data;
}
};
5. WebSocket状态管理
TypeScript
复制代码
// 状态检查
function sendSafe(ws, data) {
if (!ws) {
throw new Error('WebSocket not initialized');
}
switch (ws.readyState) {
case WebSocket.CONNECTING:
// 可以加入队列等待
return new Promise((resolve) => {
ws.addEventListener('open', () => {
ws.send(data);
resolve();
}, { once: true });
});
case WebSocket.OPEN:
ws.send(data);
return Promise.resolve();
case WebSocket.CLOSING:
case WebSocket.CLOSED:
throw new Error('WebSocket is closing or closed');
default:
throw new Error('Unknown WebSocket state');
}
}
6. 安全注意事项
TypeScript
复制代码
// 1. WSS 而非 WS(生产环境)
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
const wsUrl = `${protocol}//${window.location.host}/ws`;
// 2. 验证消息来源
ws.onmessage = (event) => {
try {
const data = JSON.parse(event.data);
// 验证消息结构
if (!isValidMessage(data)) {
console.warn('Invalid message structure');
return;
}
// 限制消息大小
if (event.data.length > MAX_MESSAGE_SIZE) {
console.warn('Message too large');
return;
}
} catch (error) {
console.error('Message parse error:', error);
}
};
// 3. 认证令牌
function initWebSocket(token) {
const ws = new WebSocket(`${wsUrl}?token=${token}`);
// 定期刷新token
setInterval(() => {
if (ws.readyState === WebSocket.OPEN) {
ws.send(JSON.stringify({
type: 'refresh_token',
token: getNewToken()
}));
}
}, TOKEN_REFRESH_INTERVAL);
}