WebSocket|HTTP协议篇
# WebSocket
30 秒速记
WebSocket是建立在TCP之上的轻量级通信协议,不是浏览器提供的一组套接字函数。- 它允许通信双方持续收发数据,能力上接近使用
TCP Socket进行传输层通信。 WebSocket与HTTP在协议层级上是并列关系,不能理解成HTTP内部的一种报文格式。- 名称中的“Web”表示它面向 Web 使用环境,并不意味着其数据传输语义属于
HTTP。
WebSocket 是基于 TCP 的轻量级通信协议,与 HTTP 处于并列层级,并不是一组底层套接字函数。 它先借助一次 HTTP/1.1 Upgrade 完成握手,服务端返回 101 后,同一连接便改为传输独立的 WebSocket 帧。客户端和服务端都能主动发送文本或二进制消息,但浏览器提供的 WebSocket API 并不等于可以直接操作 TCP Socket。它仍受连接中断和队头阻塞影响,断线重连、业务确认也要由应用自行处理。
在之前讲 TCP/IP 协议栈的时候,我说过有“TCP Socket”,它实际上是一种功能接口,通过这些接口就可以使用 TCP/IP 协议栈在传输层收发数据。
那么,你知道还有一种东西叫“WebSocket”吗?
单从名字上看,“Web”指的是 HTTP,“Socket”是套接字调用,那么这两个连起来又是什么意思呢?
所谓“望文生义”,大概你也能猜出来,“WebSocket”就是运行在“Web”,也就是 HTTP 上的 Socket 通信规范,提供与“TCP Socket”类似的功能,使用它就可以像“TCP Socket”一样调用下层协议栈,任意地收发数据。
更准确地说,“WebSocket”是一种基于 TCP 的轻量级网络通信协议,在地位上是与 HTTP“平级”的。
原理拆解: WebSocket 先借用一次 HTTP/1.1 请求完成协议升级,成功后同一条 TCP 连接不再传输普通 HTTP 报文,而改用 WebSocket 帧。帧可承载文本或二进制数据,并具有消息边界;客户端和服务端都能主动发送,因此不需要用轮询模拟服务端推送。浏览器暴露的 WebSocket API 是该协议的客户端接口,并不允许网页任意操作底层 TCP Socket。
最小验证: 输入是客户端握手请求、服务端成功响应,目标是验证双方通过 Upgrade 和 Sec-WebSocket-Accept 从 HTTP 切换到独立协议。以下是一次完整的握手报文示例:
GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13
Origin: https://example.com
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
客户端提供随机的 Sec-WebSocket-Key,服务端按协议规则计算 Sec-WebSocket-Accept;预期状态码是 101。若返回普通 200、缺少升级头或校验值不匹配,升级失败,后续字节不能按 WebSocket 帧解析。
边界与排查: WebSocket 依赖 TCP,所以仍受丢包重传、连接中断和基于 TCP 的队头阻塞影响;它也不自动提供断线重连、消息持久化或业务级确认。使用 wss 时还需先完成 TLS。代理、负载均衡器和网关必须支持连接升级,并为长连接配置合理的空闲超时。验证时除检查 101 外,还应在浏览器网络面板查看帧、关闭码和心跳行为,并确认服务端对 Origin、鉴权和消息大小进行了约束。
面试官追问
追问 1架构评审里有人把浏览器的 WebSocket 对象描述成“可直接操作任意端口的 TCP Socket API”,你会如何纠正?
这种描述不准确,浏览器对象只是 WebSocket 协议的客户端接口,不允许网页任意操纵底层 TCP Socket。它基于 TCP 提供双向消息收发并保留消息边界,但仍受浏览器安全模型和协议帧格式约束。
追问 2聊天页准备建立一条长连接,你会要求前后端怎样验证从 HTTP/1.1 握手切换到 WebSocket 成功?
客户端应发送包含 Upgrade: websocket、Connection: Upgrade 和 Sec-WebSocket-Key 的请求,服务端返回 101 Switching Protocols 及正确的 Sec-WebSocket-Accept。还要在网络面板检查后续帧;返回普通 200 或校验不匹配都不能继续按 WebSocket 解析。
追问 3网关从直连改成经过负载均衡后,连接总在空闲一段时间后断开,业务方认为 WebSocket 会自动重连,你会怎么处理?
WebSocket 不自动提供断线重连,应先检查代理、负载均衡器和网关是否支持协议升级及其空闲超时。客户端需要按业务设计重连和状态恢复,同时配置心跳;重连并不等于消息可靠,仍可能出现重复或丢失。
追问 4线上监控显示握手返回 101,但浏览器随后立即关闭连接,部分大消息出现异常,你会查看哪些证据?
握手成功只证明完成协议切换,应继续查看浏览器网络面板中的帧、关闭码和心跳,并核对服务端日志。还要检查鉴权、Origin 校验、消息大小限制以及代理超时;若使用 wss,TLS 配置和链路中间设备也必须纳入排查。
追问 5实时协作功能在短轮询和 WebSocket 之间选型,产品要求服务端随时主动推送,但又假设消息天然可靠,你会如何取舍?
需要持续双向通信时,WebSocket 可让客户端和服务端在同一连接上主动发送消息,避免用轮询模拟推送。它依赖 TCP,仍可能连接中断,也不自带消息持久化和业务级确认;可靠投递、重连与补偿必须由应用层设计。
追问 6前端同学说“WebSocket 属于 HTTP 报文的一种,所以建立连接后仍按普通请求响应排查”,你会怎样串联两种协议的关系?
应区分握手阶段和传输阶段:WebSocket 借用一次 HTTP/1.1 请求完成升级,成功后同一条 TCP 连接改为传输 WebSocket 帧。此后它与 HTTP 在协议地位上平级,排查重点也从状态码转向帧、关闭码、心跳和连接状态。
# 为什么要有 WebSocket
30 秒速记
WebSocket主要弥补HTTP请求—应答模式不适合实时双向通信的问题。- 传统请求—应答由客户端发起,服务器难以在新数据出现时主动通知客户端。
- 动态页面、即时消息和网络游戏需要低等待的数据下发,仅靠常规
HTTP交互较难满足。 - 轮询通过持续发送
HTTP请求近似实时更新,但大量无结果请求会浪费带宽和CPU。 HTTP/2、HTTP/3虽引入Stream、Server Push等能力,原文所述范围内请求—应答仍是主要工作方式。WebSocket最初属于HTML5体系,之后成为独立标准RFC 6455。
WebSocket 的出现,本质上是为了弥补 HTTP 请求—应答模式不适合实时双向通信的问题。 普通 HTTP 通常要由客户端先发起请求,服务器有新消息时无法直接沿业务通道主动下发;高频轮询虽然能模拟实时更新,却会产生大量无效请求,浪费带宽和 CPU。WebSocket 通过一次协议升级建立持久的全双工连接,适合即时消息、动态页面和网络游戏等场景。低频更新用普通请求即可,只有单向持续推送时也可以考虑更简单的 SSE。
不过,已经有了被广泛应用的 HTTP 协议,为什么要再出一个 WebSocket 呢?它有哪些好处呢?
其实 WebSocket 与 HTTP/2 一样,都是为了解决 HTTP 某方面的缺陷而诞生的。HTTP/2 针对的是“队头阻塞”,而 WebSocket 针对的是“请求 - 应答”通信模式。
那么,“请求 - 应答”有什么不好的地方呢?
“请求 - 应答”是一种“半双工”的通信模式,虽然可以双向收发数据,但同一时刻只能一个方向上有动作,传输效率低。更关键的一点,它是一种“被动”通信模式,服务器只能“被动”响应客户端的请求,无法主动向客户端发送数据。
虽然后来的 HTTP/2、HTTP/3 新增了 Stream、Server Push 等特性,但“请求 - 应答”依然是主要的工作方式。这就导致 HTTP 难以应用在动态页面、即时消息、网络游戏等要求“实时通信”的领域。
在 WebSocket 出现之前,在浏览器环境里用 JavaScript 开发实时 Web 应用很麻烦。因为浏览器是一个“受限的沙盒”,不能用 TCP,只有 HTTP 协议可用,所以就出现了很多“变通”的技术,“轮询”(polling)就是比较常用的的一种。
简单地说,轮询就是不停地向服务器发送 HTTP 请求,问有没有数据,有数据的话服务器就用响应报文回应。如果轮询的频率比较高,那么就可以近似地实现“实时通信”的效果。
但轮询的缺点也很明显,反复发送无效查询请求耗费了大量的带宽和 CPU 资源,非常不经济。
所以,为了克服 HTTP“请求 - 应答”模式的缺点,WebSocket 就“应运而生”了。它原来是 HTML5 的一部分,后来“自立门户”,形成了一个单独的标准,RFC 文档编号是 6455
原理拆解: HTTP 的一次交互通常由客户端请求触发,响应结束后,服务器没有一条可随时写入业务消息的应用层通道。轮询把“服务器主动通知”转换为客户端反复询问;长轮询虽然让请求挂起到有数据再响应,减少了空响应,但每轮仍要重新处理请求、超时和连接状态。WebSocket 先借助 HTTP/1.1 Upgrade 完成握手,再切换为可双向发送帧的持久连接,因此聊天消息、行情变化或游戏状态可以在产生时立即下发。
最小验证: 输入以下握手报文,验证服务器接受升级时返回 101,此后连接不再按普通 HTTP 响应结束。Sec-WebSocket-Key 是一次性随机值,响应中的 Sec-WebSocket-Accept 应按 RFC 6455 规则计算。
GET /chat HTTP/1.1
Host: example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13
Origin: https://example.com
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
关键结果是状态码 101 和两个升级首部;缺少升级支持、版本不匹配或鉴权失败时,服务器会返回普通 HTTP 错误响应,不能继续发送 WebSocket 帧。
边界与排查: WebSocket 并非所有更新场景的默认答案。低频通知可以使用普通请求;只有服务器单向持续下发时,SSE 也可能更简单。WebSocket 还需要处理心跳、断线重连、背压、代理空闲超时和连接级容量。工程验证应同时观察握手耗时、在线连接数、消息往返延迟、重连率及每连接内存,并用抓包确认握手后传输的是 WebSocket 帧,而不是高频轮询请求。
