WebSocket 握手过程是怎样的?HTTP 升级机制详解
WebSocket 握手基于 HTTP 协议升级机制。客户端发送一个普通的 HTTP GET 请求,携带几个关键头部:Upgrade: websocket 表示要求协议升级,Connection: Upgrade 表示连接需切换协议,Sec-WebSocket-Key 是一个随机的 Base64 编码值(16 字节),Sec-WebSocket-Version: 13 指定协议版本,Origin 标识请求来源。服务器收到后,如果同意升级,返回 101 Switching Protocols 状态码,并携带 Sec-WebSocket-Accept 头部,其值由客户端的 Key 拼接固定 GUID 258EAFA5-E914-47DA-95CA-C5AB0DC85B11,经 SHA-1 哈希后再 Base64 编码得到。这个计算过程既确认了服务器理解 WebSocket 协议,也防止了误响应。握手完成后,底层 TCP 连接从 HTTP 模式切换为 WebSocket 模式,双方可以全双工通信,不再遵循 HTTP 请求-响应模型。安全层面:服务端应验证 Origin 头部防止跨站劫持(CSRF),Sec-WebSocket-Key 的校验确保对方确实是 WebSocket 客户端而非普通浏览器,生产环境建议使用 wss:// 加密传输。
追问
Sec-WebSocket-Accept 的计算为什么不是直接返回 Key?
直接回传 Key 无法证明服务器理解 WebSocket 协议——任何 HTTP 服务器都会原样返回请求头。拼接固定 GUID 再做 SHA-1 + Base64,是一种轻量级"握手证明":只有知道协议规范的 WebSocket 服务端才会执行这个计算,普通 HTTP 服务器或代理不会。同时客户端也会校验返回的 Accept 值,不匹配则拒绝连接。
Origin 头在握手中的作用是什么?
Origin 让服务端判断握手请求是否来自可信源。WebSocket 不受同源策略约束,任何网页都能发起连接,所以服务端必须在握手阶段校验 Origin,拒绝非授权来源,防止恶意页面利用已认证的用户会话建立 WebSocket 连接(即 CSRF 攻击)。
为什么握手用 HTTP 而不是直接新建 TCP 连接?
复用 HTTP 可以利用现有基础设施:经过 HTTP 代理、防火墙、负载均衡器时不会被视为未知协议而被拦截。同时 HTTP 80/443 端口通常是开放的,降低了部署门槛。本质上是用 HTTP 作为"引导协议",完成协商后再切换到 WebSocket 二进制帧协议。
wss 和 ws 的区别是什么?
ws:// 是明文传输,wss:// 在 TCP 之上加了 TLS 加密层,等价于 HTTP 与 HTTPS 的关系。握手阶段 wss 的 HTTP 升级请求走 HTTPS,后续 WebSocket 帧同样加密传输。生产环境必须用 wss,否则数据可被中间人窃听或篡改。