目录
[一、HTTP 协议的核心特点与局限](#一、HTTP 协议的核心特点与局限)
[1.1 HTTP 协议的核心特点](#1.1 HTTP 协议的核心特点)
[1.2 HTTP 协议在实时通信场景下的局限](#1.2 HTTP 协议在实时通信场景下的局限)
[二、SSE:基于 HTTP 的单向实时推送](#二、SSE:基于 HTTP 的单向实时推送)
[2.1 什么是 SSE?](#2.1 什么是 SSE?)
[2.2 SSE 的核心原理与协议规范](#2.2 SSE 的核心原理与协议规范)
[2.2.1 连接建立](#2.2.1 连接建立)
[2.2.2 数据格式规范](#2.2.2 数据格式规范)
[2.2.3 原生能力:自动断线重连](#2.2.3 原生能力:自动断线重连)
[2.2.4 跨域支持](#2.2.4 跨域支持)
[2.3 SSE 的优缺点](#2.3 SSE 的优缺点)
[2.4 SSE 的适用场景](#2.4 SSE 的适用场景)
[3.1 什么是 WebSocket?](#3.1 什么是 WebSocket?)
[3.2 WebSocket 的核心原理与协议规范](#3.2 WebSocket 的核心原理与协议规范)
[3.2.1 握手阶段:基于 HTTP 的协议升级](#3.2.1 握手阶段:基于 HTTP 的协议升级)
[3.2.2 数据传输:基于帧的双向通信](#3.2.2 数据传输:基于帧的双向通信)
[3.2.3 跨域支持](#3.2.3 跨域支持)
[3.3 WebSocket 的优缺点](#3.3 WebSocket 的优缺点)
[3.4 WebSocket 的适用场景](#3.4 WebSocket 的适用场景)
[五、什么时候用 HTTP?什么时候用 SSE?什么时候用 WebSocket?](#五、什么时候用 HTTP?什么时候用 SSE?什么时候用 WebSocket?)
[优先选择 HTTP 的场景](#优先选择 HTTP 的场景)
[优先选择 SSE 的场景](#优先选择 SSE 的场景)
[必须选择 WebSocket 的场景](#必须选择 WebSocket 的场景)
[6.1 HTTP](#6.1 HTTP)
[6.2 SSE](#6.2 SSE)
[6.3 WebSocket](#6.3 WebSocket)
一、HTTP 协议的核心特点与局限
在讲解 SSE 和 WebSocket 之前,我们先回顾一下 Web 的基石 ------HTTP 协议,这是理解另外两个协议的基础。
1.1 HTTP 协议的核心特点
HTTP(HyperText Transfer Protocol,超文本传输协议)是 Web 应用最基础的应用层协议,它的核心设计非常简单:
- 通信模式:严格的「请求 - 响应」单向模式 ------ 只能由客户端主动发起请求,服务端接收请求后处理并返回响应,服务端永远无法主动向客户端发送数据。
- 协议基础:基于 TCP 协议,默认端口 80(明文 HTTP)或 443(加密 HTTPS)。
- 无状态:每个请求都是独立的,服务端不会保存客户端的状态信息,需要通过 Cookie、Session、Token 等机制来维持状态。
- 连接管理 :
- HTTP/1.0 默认是短连接:每次请求响应后立即关闭 TCP 连接,下次请求需要重新建立连接,开销大。
- HTTP/1.1 引入了
Connection: keep-alive长连接:请求响应后 TCP 连接保持不断开,后续请求复用同一个连接,减少了连接建立的开销,但本质上还是「请求 - 响应」模式。- HTTP/2 引入了多路复用:同一个 TCP 连接上可以同时传输多个请求和响应,进一步提升了性能,但依然没有改变「请求 - 响应」的核心模式。
1.2 HTTP 协议在实时通信场景下的局限
正是因为 HTTP 严格的「请求 - 响应」模式,它天然不适合实时通信场景。为了在 HTTP 下实现「伪实时」,开发者们想出了两种折中方案,但都有明显的缺点:
- 短轮询:客户端每隔固定时间(比如 1 秒)向服务端发一次 HTTP 请求,查询是否有新数据。优点是简单,缺点是无效请求多、延迟高、浪费服务器资源。
- 长轮询:客户端发起 HTTP 请求后,服务端会保持连接不返回,直到有新数据或超时才响应,客户端收到响应后立即发起新的请求。比短轮询高效,但依然没有摆脱「请求 - 响应」的模式,连接频繁断开重连,服务器资源占用依然较高。
而 SSE 和 WebSocket,正是为了彻底解决 HTTP 的这些局限而生的。
二、SSE:基于 HTTP 的单向实时推送
2.1 什么是 SSE?
SSE 的全称是Server-Sent Events(服务器发送事件) ,是 HTML5 标准中定义的、完全基于 HTTP 协议的、服务端到客户端的单向实时通信协议。
可以把它类比成「广播电台」:电台(服务端)建立一个持续的广播频道,听众(客户端)接入后,就能持续收到电台推送的内容;但听众不能通过这个频道给电台说话,想要互动只能单独打电话(发起普通 HTTP 请求)。
它的核心设计思路:
利用 HTTP 长连接,服务端通过
text/event-stream的 MIME 类型,源源不断地向客户端推送文本数据,浏览器原生提供EventSourceAPI 进行接收和处理。
2.2 SSE 的核心原理与协议规范
SSE 的本质是一个特殊的 HTTP GET 请求,它完全复用 HTTP 协议,不需要额外的协议升级,核心规范分为以下几个部分:
2.2.1 连接建立
客户端通过EventSourceAPI 向服务端发起一个 HTTP GET 请求,请求头会自动带上Accept: text/event-stream,表明自己想要接收 SSE 数据流。服务端收到请求后,返回符合以下要求的 HTTP 响应:
- 状态码:200 OK
Content-Type: text/event-stream; charset=utf-8:指定数据流类型,必须是 UTF-8 编码Cache-Control: no-cache:禁用缓存,确保数据实时推送Connection: keep-alive:保持长连接不断开- 可选:CORS 相关头,解决跨域问题
响应头返回后,TCP 连接不会关闭,服务端可以随时向这个连接中写入数据,实现持续推送。
2.2.2 数据格式规范
SSE 的数据流有严格的格式要求,所有数据都是 UTF-8 编码的文本,以换行符分隔,以两个连续的换行符\n\n标识一条完整消息的结束。
每条消息可以包含 4 个核心字段,每个字段占一行,格式为
字段名: 字段值\n:
| 字段名 | 作用 | 说明 |
|---|---|---|
data |
消息内容 | 核心字段,存放推送的正文,支持多行,最终会拼接成完整字符串 |
event |
自定义事件名 | 不填默认触发客户端的message事件,填写后会触发对应名称的自定义事件 |
id |
消息唯一 ID | 客户端会记录最后收到的 ID,断线重连时会自动带上Last-Event-ID请求头,服务端可据此补发丢失的消息 |
retry |
断线重连间隔 | 单位为毫秒,告诉浏览器断线后自动重连的等待时间,不填默认 3 秒 |
2.2.3 原生能力:自动断线重连
这是 SSE 最省心的核心能力之一:浏览器原生实现了断线自动重连机制 。当网络中断、服务端异常导致连接断开时,浏览器会自动按照
retry设置的间隔(默认 3 秒)重新发起连接,并且会在请求头中自动带上Last-Event-ID: 最后收到的消息ID,服务端可以根据这个 ID,把断开期间丢失的消息补发给客户端,实现消息的连续性。
2.2.4 跨域支持
SSE 完全兼容 HTTP 的 CORS 跨域规范,服务端只需要在响应头中设置
Access-Control-Allow-Origin,即可允许跨域请求,和普通 HTTP 接口的跨域处理完全一致,无需额外配置。
2.3 SSE 的优缺点
优点:
- 原生 HTTP 协议,兼容性极强:完全基于 HTTP,无需额外的协议升级,兼容所有 HTTP 代理、网关、负载均衡器、防火墙,部署成本几乎为 0。
- 开发成本极低 :浏览器原生提供
EventSourceAPI,几行代码就能实现接收,服务端只需要按照规范返回数据流,无需引入复杂的第三方库。- 内置高可用能力:原生支持断线自动重连、消息 ID 补发,无需开发者手动实现重连逻辑,大幅降低开发工作量。
- 轻量低开销:连接建立后,后续推送的消息只有数据本身,没有 HTTP 请求头的额外开销,带宽占用远低于轮询。
- 消息分类清晰:支持自定义事件类型,不同类型的消息可以触发不同的事件回调,业务逻辑更清晰。
缺点:
- 单向通信限制:只能由服务端向客户端推送数据,客户端想要向服务端发送数据,必须单独发起普通 HTTP 请求,无法通过 SSE 连接双向传输。
- 仅支持文本数据:原生只支持 UTF-8 文本,无法直接传输二进制数据,需要传输的话必须先进行 Base64 编码,会增加额外开销。
- HTTP/1.1 并发限制:在 HTTP/1.1 协议下,浏览器对同一个域名的 SSE 长连接有最大并发数限制(通常为 6 个),超过限制的连接会被阻塞;HTTP/2 协议通过多路复用解决了这个问题,同一个域名下的所有 SSE 连接共享一个 TCP 连接,无并发限制。
- 低版本浏览器兼容问题:IE 浏览器完全不支持 SSE,但目前 IE 的市场占比已经极低,绝大多数业务场景无需考虑。
2.4 SSE 的适用场景
SSE 适配仅需要服务端单向推送,客户端极少向服务端发送数据的场景,典型场景包括:
- 股票、基金、加密货币等实时行情大盘
- 系统公告、新闻推送、站内信通知
- 直播弹幕、在线人数统计
- 服务器监控、日志实时输出
- 在线文档的协作者在线状态同步
- 赛事直播的实时比分推送
三、WebSocket:全双工实时通信
3.1 什么是 WebSocket?
WebSocket 是 HTML5 标准中定义的基于 TCP 的全双工应用层协议,它彻底摆脱了 HTTP 的「请求 - 响应」模式,在客户端和服务端之间建立一个持久的、双向的通信通道,连接建立后,双方可以随时向对方发送数据,没有任何限制。
你可以把它类比成「打电话」:电话接通后,你(客户端)和对方(服务端)可以随时说话,双向传递信息,不需要一方先提问,另一方才能回答,延迟极低。
WebSocket 的设计思路是:
通过 HTTP 协议完成握手升级,将 TCP 连接从 HTTP 协议切换为 WebSocket 协议,之后完全脱离 HTTP,基于帧进行双向数据传输。
3.2 WebSocket 的核心原理与协议规范
3.2.1 握手阶段:基于 HTTP 的协议升级
WebSocket 的连接建立必须通过一次 HTTP 请求完成握手,这是为了兼容现有的 HTTP 基础设施,确保握手请求能正常通过代理、防火墙。
客户端握手请求:客户端向服务端发起一个 HTTP GET 请求,携带以下核心请求头:
Upgrade: websocket+Connection: Upgrade:核心头,告诉服务端,这个请求要升级为 WebSocket 协议;Sec-WebSocket-Key:客户端生成的随机 Base64 字符串,用于服务端生成握手响应的校验值,防止跨域请求伪造;Sec-WebSocket-Version:WebSocket 协议版本,固定为 13;Origin:客户端的源地址,服务端可以据此做跨域权限控制。
服务端握手响应:服务端校验请求合法后,返回 101 状态码的响应,完成协议升级:
101 Switching Protocols:HTTP 协议切换的标准状态码,表示握手成功;Sec-WebSocket-Accept:服务端根据客户端的Sec-WebSocket-Key,通过固定算法生成的校验值,客户端会校验这个值,确保握手的合法性。
握手完成后,TCP 连接不会关闭,HTTP 协议就此退出,后续所有数据都通过 WebSocket 协议的帧格式进行双向传输。
3.2.2 数据传输:基于帧的双向通信
WebSocket 的数据传输不是 HTTP 的流模式,而是基于「帧」 的模式,每一条消息都会被拆分成一个或多个帧进行传输,接收方再将帧拼接成完整的消息。
帧的类型主要分为以下几类,无需深入底层字节结构,只需了解核心作用:
- 文本帧:用于传输 UTF-8 文本数据,最常用的帧类型;
- 二进制帧:用于传输二进制数据(比如图片、文件、音视频流),无需编码,直接传输;
- 关闭帧:用于关闭连接,双方可以携带关闭状态码和原因;
- Ping/Pong 帧:心跳检测帧,一方发送 Ping 帧,另一方必须立即回复 Pong 帧,用于检测连接是否存活。
心跳机制:
由于网络中的代理、防火墙、负载均衡器,会自动关闭长时间没有数据传输的空闲 TCP 连接,所以 WebSocket 需要通过 Ping/Pong 帧定时发送心跳,保持连接存活。浏览器原生会自动回复 Ping 帧,无需开发者手动处理。
3.2.3 跨域支持
WebSocket 原生支持跨域,没有同源策略的限制 ,客户端可以向任意域名的 WebSocket 服务发起连接。为了安全,服务端必须校验请求头中的
Origin字段,只允许信任的域名接入,防止恶意网站发起跨域 WebSocket 攻击。
3.3 WebSocket 的优缺点
优点:
- 真正的全双工通信:连接建立后,客户端和服务端可以随时双向发送数据,没有请求 - 响应的限制,延迟极低,是真正的实时通信。
- 支持二进制数据:原生支持文本和二进制数据传输,无需编码,完美适配文件、音视频流等二进制场景。
- 极低的带宽开销:握手完成后,后续数据帧的头部开销极小(只有 2-10 字节),没有 HTTP 请求头的冗余开销,大幅节省带宽。
- 无并发连接限制:一个 WebSocket 连接就能实现双向通信,不存在 SSE 的并发连接限制,资源占用更低。
- 全平台兼容性好:所有现代浏览器、移动端、服务端都完美支持 WebSocket 协议,生态成熟。
缺点:
- 开发成本高 :浏览器原生只提供了基础的
WebSocketAPI,没有内置断线重连、消息补发、心跳保活、消息序列化等能力,这些都需要开发者手动实现,开发工作量远大于 SSE。- 基础设施兼容性差:握手完成后就脱离了 HTTP 协议,传统的 HTTP 代理、防火墙、负载均衡器需要额外配置才能支持 WebSocket,部分企业内网的防火墙甚至会直接屏蔽 WebSocket 连接。
- 协议复杂度高:相比 SSE,WebSocket 的帧格式、状态管理、安全校验都更复杂,出现问题时排查难度更高。
- 资源占用更高:需要服务端维持大量的长 TCP 连接,对服务端的并发处理能力要求更高。
3.4 WebSocket 的适用场景
WebSocket 适配需要频繁双向实时通信、低延迟交互的场景,典型场景包括:
- 在线聊天、IM 即时通讯、客服系统
- 实时多人在线游戏
- 在线协作编辑(文档、表格、设计稿)
- 音视频通话、直播连麦
- 物联网设备的远程控制与状态上报
- 在线白板、实时投票、互动答题
四、三大协议差异对比
| 对比维度 | HTTP(含轮询 / 长轮询) | SSE(Server-Sent Events) | WebSocket |
|---|---|---|---|
| 通信模式 | 严格的「请求 - 响应」单向模式,仅客户端→服务端发起请求 | 单向通信,仅服务端→客户端推送数据 | 全双工通信,客户端↔服务端双向实时传输 |
| 协议基础 | 完全基于 HTTP 协议 | 完全基于 HTTP 协议,无协议切换 | 握手基于 HTTP,传输阶段是独立的 WebSocket 协议 |
| 连接建立 | 每次请求或复用长连接 | 一次 HTTP GET 请求建立长连接 | 一次 HTTP 握手请求升级为 WebSocket 连接 |
| 连接状态 | 无状态,需通过 Cookie/Token 维持 | 长连接保持,有状态 | 长连接保持,有状态 |
| 数据传输方向 | 仅客户端主动发起,服务端被动响应 | 仅服务端主动推送,客户端被动接收 | 双方可随时主动发送数据 |
| 数据类型 | 支持文本和二进制(HTTP 请求 / 响应体) | 仅支持 UTF-8 文本,二进制需 Base64 编码 | 原生支持文本和二进制数据 |
| 原生重连机制 | 无,需手动实现 | 浏览器原生支持断线自动重连 + 消息 ID 补发 | 无原生重连机制,需开发者手动实现 |
| 原生心跳机制 | 无 | 无,需手动实现 | 原生支持 Ping/Pong 心跳帧 |
| 头部开销 | 每次请求都有完整的 HTTP 请求头,开销大 | 连接建立后,仅消息本身无额外开销 | 连接建立后,帧头部仅 2-10 字节,开销极低 |
| 浏览器并发限制 | HTTP/1.1 下同域名最多 6-8 个并发请求,HTTP/2 无限制 | HTTP/1.1 下同域名最多 6 个连接,HTTP/2 无限制 | 无并发限制,一个连接即可满足需求 |
| 基础设施兼容性 | 完美兼容所有 HTTP 代理、防火墙、负载均衡器 | 完美兼容所有 HTTP 代理、防火墙、负载均衡器 | 需额外配置,部分环境会屏蔽 WebSocket 连接 |
| 开发成本 | 低(轮询)/ 中(长轮询) | 极低,原生 API 几行代码即可实现 | 较高,需手动实现重连、心跳、消息管理等 |
| 典型适用场景 | 普通 Web 页面请求、非实时数据查询、低频数据更新 | 单向推送场景:行情大盘、公告通知、日志监控、弹幕 | 双向交互场景:IM 聊天、多人游戏、协作编辑、音视频通话 |
五、什么时候用 HTTP?什么时候用 SSE?什么时候用 WebSocket?
优先选择 HTTP 的场景
业务符合以下任意一条,优先选择 HTTP:
- 核心需求是普通的 Web 页面请求、数据查询,没有实时性要求;
- 数据更新频率很低(比如几分钟、几小时才更新一次),用短轮询就能满足需求;
- 对开发成本和部署兼容性要求极高,不想引入任何额外的实时通信方案。
优先选择 SSE 的场景
业务符合以下任意一条,优先选择 SSE:
- 核心需求是服务端向客户端单向推送数据,客户端很少向服务端发送数据(比如行情大盘、公告推送、日志实时输出);
- 想要最低的开发成本和最快的上线速度,不想处理复杂的连接管理、重连逻辑;
- 部署环境对 HTTP 兼容性要求高,比如企业内网、有严格的防火墙 / 代理配置,无法支持 WebSocket;
- 业务需要可靠的消息连续性,比如监控告警、订单状态推送,SSE 的原生消息 ID 和重连补发机制,能大幅降低开发成本。
必须选择 WebSocket 的场景
业务符合以下任意一条,必须选择 WebSocket:
- 核心需求是频繁的双向实时通信,客户端和服务端都需要频繁向对方发送数据(比如 IM 聊天、在线游戏、协作编辑);
- 需要传输二进制数据,比如图片、文件、音视频流;
- 对延迟要求极高,比如实时对战游戏、连麦互动,无法接受 HTTP 请求的额外延迟;
- 同一个客户端需要同时接收大量不同类型的实时数据,用 SSE 会触发并发连接限制,而 WebSocket 一个连接就能解决。
六、注意事项
6.1 HTTP
- 合理使用缓存 :对于非实时数据,充分利用 HTTP 缓存(
Cache-Control、ETag、Last-Modified),减少服务器压力;- 优先使用 HTTP/2 或 HTTP/3:通过多路复用、头部压缩等特性,提升 HTTP 请求的性能;
- 轮询优化:如果必须使用轮询,建议设置动态的轮询间隔(比如数据更新频繁时缩短间隔,更新缓慢时延长间隔),减少无效请求。
6.2 SSE
- 优先使用 HTTP/2 协议:彻底解决 HTTP/1.1 的 6 个并发连接限制,同时提升连接性能;
- 设置合理的 retry 间隔:生产环境建议设置 5-10 秒的重连间隔,避免网络波动时客户端频繁重连,给服务端造成压力;
- 消息 ID 设计:建议使用递增的数字 ID 或时间戳,方便断线重连时快速补发丢失的消息;
- 超时处理:服务端需要设置合理的连接超时时间,清理长期无响应的僵尸连接,释放服务器资源。
6.3 WebSocket
- 必须使用 wss 加密协议 :
wss://是 WebSocket over TLS,和https://一样,能防止中间人攻击、数据窃听和篡改,生产环境严禁使用明文的ws://;- 严格的跨域校验 :服务端必须校验
Origin请求头,只允许信任的域名接入,防止跨域 WebSocket 攻击;- 完善的心跳保活机制:建议设置 30-60 秒的心跳间隔,及时清理僵尸连接,避免被中间节点断开空闲连接;
- 可靠的重连与消息幂等:重连逻辑需要实现指数退避算法,避免频繁重连;发送的消息需要设计唯一 ID,确保重连后消息不会重复处理;
- 负载均衡会话保持:生产环境多实例部署时,需要配置负载均衡的会话保持(sticky session),确保同一个客户端的 WebSocket 连接始终路由到同一个服务端实例;
- 消息分片与限流:对于大文件、大数据量的传输,需要实现消息分片,同时设置客户端消息限流,防止恶意客户端发送大量数据打满服务器带宽。
七、总结
HTTP、SSE、WebSocket 并不是互相替代的关系,而是互补的三套 Web 通信方案。
- HTTP是 Web 的基石,简单、通用、兼容性强,是所有非实时场景的首选;即使在实时场景下,轮询和长轮询也是简单场景的折中方案。
- SSE「小而美」,单向推送,它基于 HTTP、简单易用、原生支持重连补发,用极低的开发成本就能解决绝大多数的服务端推送场景。
- WebSocket「大而全」,全双工通信,它彻底摆脱了 HTTP 的限制,实现了真正的双向实时通信,是复杂交互场景的唯一选择,但也带来了更高的开发成本和部署复杂度。
感谢阅读,本文如有错漏之处,烦请斧正。