WebSocket 握手原理的核心在于通过 HTTP 协议完成初始连接后,升级为全双工通信协议。整个过程可分为请求、验证和转换三个阶段:
1. **HTTP 升级请求**
客户端发送特殊HTTP请求头:
```http
GET /chat HTTP/1.1
Host: example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13
关键字段说明:
Upgrade: websocket声明协议升级意图Sec-WebSocket-Key包含Base64编码的16字节随机值Version指定协议版本(13表示RFC6455)
- 服务端验证响应 服务端需计算响应密钥:
const crypto = require('crypto');
function generateAccept(key) {
return crypto.createHash('sha1')
.update(key + '258EAFA5-E914-47DA-95CA-C5AB0DC85B11')
.digest('base64');
}
// 示例输出:s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
返回响应头:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
状态码101表示协议切换成功,响应密钥验证通过后建立持久连接。
- 协议转换机制 握手完成后,底层TCP连接保持开放状态,但通信协议转为WebSocket格式:
- 数据帧使用二进制格式传输
- 支持文本/二进制两种数据类型
- 内置心跳机制(Ping/Pong帧)
安全验证要点:
- 必须校验
Origin头防止CSRF攻击 - 响应密钥算法强制使用SHA-1哈希
- 协议版本需严格匹配
实际应用示例(Node.js实现):
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });
wss.on('connection', (ws) => {
ws.on('message', (message) => {
console.log(`Received: ${message}`);
ws.send('Message received');
});
});
异常处理场景:
- 无效的Upgrade头返回400错误
- 版本不匹配时返回426状态码
- 加密握手失败立即关闭连接
性能优化建议:
- 复用TCP连接减少握手开销
- 启用压缩扩展(permessage-deflate)
- 合理设置心跳间隔(建议30秒)
协议特点总结:
- 单次握手建立持久连接
- 基于帧的数据传输模式
- 支持跨域通信(需CORS配合)
- 比HTTP长轮询节省90%以上流量