webSocket 握手的原理是什么?

76 阅读2分钟
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)
  1. 服务端验证响应 服务端需计算响应密钥:
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表示协议切换成功,响应密钥验证通过后建立持久连接。

  1. 协议转换机制 握手完成后,底层TCP连接保持开放状态,但通信协议转为WebSocket格式:
  • 数据帧使用二进制格式传输
  • 支持文本/二进制两种数据类型
  • 内置心跳机制(Ping/Pong帧)

安全验证要点:

  1. 必须校验Origin头防止CSRF攻击
  2. 响应密钥算法强制使用SHA-1哈希
  3. 协议版本需严格匹配

实际应用示例(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状态码
  • 加密握手失败立即关闭连接

性能优化建议:

  1. 复用TCP连接减少握手开销
  2. 启用压缩扩展(permessage-deflate)
  3. 合理设置心跳间隔(建议30秒)

协议特点总结:

  • 单次握手建立持久连接
  • 基于帧的数据传输模式
  • 支持跨域通信(需CORS配合)
  • 比HTTP长轮询节省90%以上流量