
一、WebSocket基本概念
WebSocket是一种网络通信协议,提供 全双工(full-duplex)通信通道,允许客户端和服务器之间进行实时双向数据传输。与传统的HTTP请求-响应模式不同,WebSocket建立连接后保持持久连接,双方可以随时发送数据。
核心特点
双向通信:服务器和客户端可以随时发送消息。
持久连接:一次握手后保持连接状态,减少开销。
低延迟:避免HTTP请求的头部开销和连接建立时间。
二进制支持:可传输文本和二进制数据。
单一TCP连接:所有通信通过同一连接进行。
轻量级:数据帧头部较小(2-14字节)。
二、WebSocket 协议基础
握手过程:
客户端发送HTTP请求,包含WebSocket升级头信息。
服务器响应HTTP 101状态码,表示协议切换。
建立TCP连接,后续通信使用WebSocket协议。
# 客户端请求
GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13
# 服务器响应
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=三、WebSocket与HTTP的区别
特性 | HTTP | WebSocket |
|---|---|---|
通信模式 | 请求-响应 | 全双工 |
连接类型 | 短连接 | 长连接 |
头部开销 | 每次请求都有完整头部 | 仅握手时有头部 |
实时性 | 低(轮询/长轮询) | 高 |
服务器推送 | 不支持(需客户端主动请求) | 原生支持 |
协议标识符 | http:// 或 https:// | ws:// 或 wss:// |
四、JavaScript WebSocket API
WebSocket示例
服务端:
const WebSocket = require('ws');
// 创建WebSocket服务器,监听端口8080
const wss = new WebSocket.Server({ port: 8080 });
console.log('WebSocket server is running on ws://localhost:8080');
// 客户端连接事件
wss.on('connection', (ws) => {
console.log('A new client connected');
// 发送欢迎消息给新客户端
ws.send('Welcome to the WebSocket server!');
// 接收客户端消息事件
ws.on('message', (message) => {
console.log(`Received: ${message}`);
// 广播消息给所有连接的客户端
wss.clients.forEach((client) => {
if (client.readyState === WebSocket.OPEN) {
client.send(`Client: ${message}`);
}
});
});
// 客户端断开连接事件
ws.on('close', () => {
console.log('A client disconnected');
});
// 错误处理
ws.on('error', (error) => {
console.error('WebSocket error:', error);
});
});客户端:
<div id="messages"></div>
<input type="text" id="input" placeholder="输入消息...">
<button onclick="sendMessage()">发送</button>
<button onclick="closeConnection()">关闭连接</button>
<button onclick="connect()">重新连接</button>
<script>
let ws;
const messagesDiv = document.getElementById('messages');
const input = document.getElementById('input');
// 连接WebSocket服务器
function connect() {
// 创建WebSocket连接
ws = new WebSocket('ws://localhost:8080');
// 连接打开事件
ws.onopen = () => {
addMessage('已连接到服务器');
};
// 接收消息事件
ws.onmessage = (event) => {
addMessage(`服务器: ${event.data}`);
};
// 连接关闭事件
ws.onclose = () => {
addMessage('与服务器的连接已关闭');
};
// 错误处理
ws.onerror = (error) => {
addMessage(`连接错误: ${error}`);
};
}
// 发送消息
function sendMessage() {
const message = input.value;
if (message && ws && ws.readyState === WebSocket.OPEN) {
ws.send(message);
addMessage(`我: ${message}`);
input.value = '';
} else {
addMessage('无法发送消息,请检查连接');
}
}
// 关闭连接
function closeConnection() {
if (ws) {
ws.close();
}
}
// 添加消息到显示区域
function addMessage(message) {
const div = document.createElement('div');
div.textContent = new Date().toLocaleTimeString() + ': ' + message;
messagesDiv.appendChild(div);
messagesDiv.scrollTop = messagesDiv.scrollHeight;
}
// 页面加载时自动连接
window.onload = connect;
// 回车键发送消息
input.addEventListener('keypress', (e) => {
if (e.key === 'Enter') {
sendMessage();
}
});
</script>五、WebSocket事件、属性和方法
WebSocket 事件
事件名称 | 描述 | 事件处理程序属性 |
|---|---|---|
open | 连接成功建立时触发 | onopen |
message | 客户端接收服务端数据时触发 | onmessage |
error | 通信发生错误时触发 | onerror |
close | 连接关闭时触发 | onclose |
WebSocket 属性
属性名称 | 类型 | 描述 |
|---|---|---|
readyState | number | 当前连接状态:
|
| ||
bufferedAmount | number | 已发送但尚未被服务器确认的字节数 |
extensions | string | 服务器选择的扩展 |
protocol | string | 服务器选择的子协议 |
url | string | WebSocket 服务器的 URL |
binaryType | string | 接收二进制数据的类型,可以是 "blob" 或 "arraybuffer" |
WebSocket 方法
方法名称 | 描述 |
|---|---|
send(data) | 向服务器发送数据 |
close([code[, reason]]) | 关闭 WebSocket 连接 |
事件示例(客户端)
// 创建 WebSocket 连接
const socket = new WebSocket('ws://example.com/socket');
// 连接建立时触发
socket.onopen = function(event) {
console.log('WebSocket 连接已建立');
socket.send('Hello Server!');
};
// 接收消息时触发
socket.onmessage = function(event) {
console.log('收到消息:', event.data);
};
// 发生错误时触发
socket.onerror = function(error) {
console.error('WebSocket 错误:', error);
};
// 连接关闭时触发
socket.onclose = function(event) {
console.log('WebSocket 连接已关闭:', event.code, event.reason);
};方法示例(客户端)
// 发送文本消息
socket.send('Hello World');
// 发送二进制数据
const buffer = new ArrayBuffer(16);
const view = new Uint8Array(buffer);
for (let i = 0; i < view.length; i++) {
view[i] = i;
}
socket.send(buffer);
// 关闭连接
socket.close(1000, '正常关闭'); // 1000为正常关闭代码六、最佳实践与注意事项
连接管理示例(客户端)
// 自动重连机制
function connectWebSocket() {
const socket = new WebSocket('ws://example.com/socket');
socket.onclose = function() {
console.log('连接关闭,5秒后重连...');
setTimeout(connectWebSocket, 5000);
};
return socket;
}
let socket = connectWebSocket();消息处理示例(客户端)
// 分片消息处理
let messageBuffer = '';
socket.onmessage = function(event) {
if (event.data instanceof Blob) {
// 处理二进制数据
const reader = new FileReader();
reader.onload = function() {
processMessage(reader.result);
};
reader.readAsText(event.data);
} else {
// 处理文本数据
processMessage(event.data);
}
};
function processMessage(data) {
// 解析JSON消息
try {
const message = JSON.parse(data);
// 根据消息类型处理
switch(message.type) {
case 'chat':
displayChatMessage(message);
break;
case 'update':
updateData(message);
break;
// 其他消息类型
}
} catch (error) {
console.error('消息解析错误:', error);
}
}心跳机制示例(客户端)
// 心跳配置
const HEARTBEAT_INTERVAL = 30000; // 30秒
let heartbeatTimer;
// 启动心跳
socket.onopen = function() {
startHeartbeat();
};
function startHeartbeat() {
heartbeatTimer = setInterval(() => {
if (socket.readyState === 1) {
socket.send(JSON.stringify({ type: 'ping' }));
}
}, HEARTBEAT_INTERVAL);
}
// 重置心跳
socket.onmessage = function(event) {
const message = JSON.parse(event.data);
if (message.type === 'pong') {
// 收到服务器回应,重置心跳
clearInterval(heartbeatTimer);
startHeartbeat();
}
};
// 关闭时清除心跳
socket.onclose = function() {
clearInterval(heartbeatTimer);
};输入验证与过滤(客户端)
// 消息验证
function validateMessage(message) {
// 检查消息大小
if (message.length > 10000) {
throw new Error('消息过长');
}
// 验证消息格式
const data = JSON.parse(message);
if (!data.type || !data.payload) {
throw new Error('无效的消息格式');
}
// 防止XSS攻击
const sanitize = (str) => {
return str.replace(/[<>]/g, '');
};
if (typeof data.payload === 'string') {
data.payload = sanitize(data.payload);
}
return data;
}二进制数据传输(客户端)
// 使用二进制传输大型数据
function sendBinaryData(data) {
if (typeof data === 'string') {
// 字符串编码
const encoder = new TextEncoder();
const buffer = encoder.encode(data);
socket.send(buffer);
} else if (data instanceof ArrayBuffer) {
socket.send(data);
} else if (data instanceof Blob) {
socket.send(data);
}
}
// 接收二进制数据
socket.binaryType = 'arraybuffer'; // 或 'blob'
socket.onmessage = (event) => {
if (event.data instanceof ArrayBuffer) {
const decoder = new TextDecoder();
const text = decoder.decode(event.data);
console.log('解码后的文本:', text);
}
};WebSocket为Web应用提供了实时双向通信能力,大幅提升了用户体验。JavaScript的WebSocket API简洁易用,结合适当的连接管理、消息处理和安全措施,可以构建高效可靠的实时应用。
彩蛋
完整示例代码,请移步Cnb: 《WebSocket完整示例》