前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
首页程序员面试题库WebSocket SSE 选型 实时推送 对比
浏览器请求与通信 API

实时推送场景下 WebSocket 与 SSE 如何选型,各自的决定性优势是什么?

只需要服务端持续向浏览器推送文本,优先考虑 SSE;双方都要频繁发消息,或者需要传输二进制数据,再考虑 WebSocket。

前端进阶之旅 · 一题精讲更新于 2026.09.10
浏览器#请求与通信 API#实时通信#HTTP
先看核心答案读代码示例
理解线索

先回答三个问题,再决定用谁

  1. 谁在持续发消息?只有服务端发,还是客户端和服务端都要频繁发
  2. 传什么数据?只是文本事件,还是包含图片、音频等二进制数据
  3. 断线后怎么恢复?只需自动重连,还是要自己维护会话、补发和去重

不要先问谁更高级或谁一定更快,通信方向通常才是第一判断条件。

核心回答

先记住这个答案

我会先看数据是否需要双向实时流动。客户端发起一次请求,之后主要由服务端持续推送文本,例如消息通知、任务进度或流式回答,通常优先用 SSE,因为它基于普通 HTTP,浏览器的 EventSource 还提供事件解析和自动重连。双方都要频繁主动发消息,或者要传图片、音频等二进制数据时,WebSocket 的全双工能力更合适。它们不是谁更先进,而是谁更符合当前的通信方式。

  • 单向文本推送优先 SSE
  • 高频双向通信或二进制传输选 WebSocket
  • “停止生成”这类偶发上行请求,不足以成为改用 WebSocket 的理由

先问三个问题,就能完成大部分选型

选型时不要先比较协议名,而要先画出消息流向。谁在什么时机发消息,往往比“实时性”三个字更有判断价值。

只有服务端需要持续推送吗?
如果客户端只是建立连接,之后主要接收服务端事件,例如构建日志、订单状态、新闻更新或任务进度,优先考虑 SSE。它正好表达“服务端不断向浏览器发送文本事件”,实现和维护成本通常更低。
双方都要频繁、独立地发消息吗?
如果客户端随时都可能发送操作,服务端也要立即广播结果,例如在线协作中的光标和编辑操作、实时游戏指令或双向语音控制,选择 WebSocket 更自然。一条连接可以同时收发消息,不需要再为上行操作单独建立请求链路。
数据只是偶尔更新吗?
如果页面几十秒甚至几分钟才更新一次,普通请求或轮询可能已经足够。实时功能不等于必须建立长连接;连接越多,服务端需要维护的状态和资源也越多。

两者真正有决定性的差异

SSE 是运行在 HTTP 响应上的文本事件流;WebSocket 则在握手完成后,通过独立的消息帧进行双向通信。两者都能让页面及时收到新数据,但它们解决的通信模型不同。

通信方向
SSE 负责服务端到浏览器的单向推送,客户端要提交数据时仍然使用普通 HTTP 请求。WebSocket 是全双工连接,双方可以在任意时刻主动发送消息。需要持续双向交互,是选择 WebSocket 最有分量的理由。
数据类型
SSE 传输的是 UTF-8 文本事件,特别适合日志、通知和文本增量。WebSocket 同时支持文本和二进制消息,因此实时音频、图片分片或自定义二进制协议更适合使用它。
重连与维护成本
浏览器的 EventSource 能在连接断开后自动尝试重连,并可以结合事件 id 告诉服务端自己已经收到哪里。原生 WebSocket 没有自动重连,需要应用自己处理心跳、重连间隔、登录状态续期和消息补发。相应地,WebSocket 给了应用更大的通信自由,也带来了更多连接管理工作。

用代码看懂 SSE:浏览器只负责接收

下面是一个任务进度页面。浏览器建立连接后,只监听服务端发来的 progress 和 done 事件;页面没有通过这条连接向服务端发送消息。

用 EventSource 接收任务进度JavaScript
const source = new EventSource('/api/tasks/42/events');

source.addEventListener('progress', event => {
  const { percent } = JSON.parse(event.data);
  progressBar.value = percent;
});

source.addEventListener('done', () => {
  source.close();
});

这段代码最值得记住的不是方法名,而是只有“接收”。服务端可以依次发送 progress 事件,任务完成后再发送 done;如果用户要取消任务,可以另外调用一个普通的取消接口,没有必要为了这一次上行操作改成 WebSocket。

用代码看懂 WebSocket:同一连接既收又发

再看协同编辑。用户的每次修改要立即上传,其他人的修改也要随时推回来,因此同一个连接同时承担上行和下行消息。

在同一条连接上发送和接收编辑操作JavaScript
const socket = new WebSocket('wss://example.com/rooms/42');

function sendEdit(change) {
  if (socket.readyState !== WebSocket.OPEN) return;
  socket.send(JSON.stringify({ type: 'edit', change }));
}

socket.addEventListener('message', event => {
  const message = JSON.parse(event.data);
  applyRemoteEdit(message.change);
});

这里既有客户端主动调用 send(),也有客户端监听 message。这就是选择 WebSocket 的决定性原因:双方都需要在一条持续连接上独立、频繁地发送消息,而不仅仅是“服务端要实时推送”。

放进真实业务里,会更容易理解

不要把选型背成“简单场景用 SSE,复杂场景用 WebSocket”。同一个产品中也可能同时使用普通请求和实时通道,关键仍然是每条数据怎样流动。

消息通知、构建日志和任务进度
这些场景主要由服务端产生新状态,浏览器负责接收和展示,使用 SSE 通常更直接。连接可以沿用现有的 HTTP 路由、状态码和代理体系;不过仍要检查反向代理是否缓冲响应,否则服务端已经发送的数据可能不会立即到达浏览器。
AI 流式回答
用户先提交完整问题,服务端随后不断返回文本增量,本质上仍以单向下行为主,可以使用 SSE 或采用相同事件格式的 fetch 流。用户点击“停止”时,另发一个取消请求通常就够了;只有需要持续上传语音、频繁修改参数或进行真正的双向并发流时,WebSocket 的优势才明显。
协同编辑、游戏和实时语音
用户操作要不断上传,其他人的状态又要及时下发,双方都在持续产生消息。此时如果坚持使用 SSE,往往还要额外维护一套上行请求和状态关联;WebSocket 用一条双向连接承载这类交互更合适。

选完协议,还要补上的边界

协议只负责传输消息,不会自动解决业务可靠性。无论选择哪一种,只要断线后不能丢数据,都需要给消息分配稳定的事件 ID 或序号,并由服务端保留一段可补发的数据,客户端负责去重和恢复。

EventSource 和 fetch 流不要混为一谈
自动重连是浏览器 EventSource 的能力。项目如果为了发送 POST 请求或自定义请求头,改用 fetch + ReadableStream 接收事件流,就需要自己处理解析、重连和续传,不能继续假设浏览器会自动完成这些工作。
长连接都要经过真实基础设施验证
SSE 可能受到代理缓冲和 HTTP/1.1 同源连接数限制;WebSocket 可能被空闲超时断开,也需要负载均衡和服务端容量支持。选型完成后,应至少验证断网重连、代理超时、登录过期和多标签页连接数量,而不是只在本机开发环境里确认“能收到消息”。
回答前,多想一步

容易答错的地方

“WebSocket 一定比 SSE 更快”
两者建立连接后都可以持续传输数据,实际延迟通常还受网络、服务端处理和业务逻辑影响。选型首先看通信方向与数据类型,不能因为 WebSocket 功能更多,就默认它在单向文本推送里体验更好。
“SSE 会自动重连,所以消息不会丢”
自动重连只代表浏览器会再次尝试连接,不代表服务端一定保存了断线期间的消息。需要可靠恢复时,还要配合事件 id、服务端历史记录和客户端去重;否则连接虽然恢复,中间的数据仍可能缺失。
“聊天功能就必须使用 WebSocket”
如果聊天是低频发送、服务端单向流式回复,普通 POST 加 SSE 或响应流也能完成。只有双方需要持续并发发送、低延迟广播或二进制传输时,WebSocket 的复杂度才真正值得承担。
试着用自己的话回答

面试官还会怎么问?

AI 对话支持“停止生成”,是不是就该从 SSE 换成 WebSocket?

不一定。停止只是一次偶发的上行操作,可以中止当前读取,再调用独立的取消接口。若除了停止之外,客户端还要持续上传语音、频繁发送控制事件,并且这些事件要和下行内容并发传输,才更有理由改用 WebSocket。

EventSource 断线后自动重连,服务端怎样避免重复发送?

服务端可以为事件分配递增的 id,并保留一段事件记录。客户端重连时会携带最后收到的事件标识,服务端从下一条开始补发;客户端仍应按 id 去重,因为网络重试不能天然保证业务上的“恰好一次”。

原生 EventSource 不能设置自定义 Authorization 请求头,怎么处理鉴权?

同源场景可以使用安全的会话 cookie;跨域时要同时正确配置凭据和跨域响应。若必须使用自定义请求头或 POST 请求,可以改用 fetch 读取事件流,但事件解析、重连和续传也要由应用自己实现。

已经用了 WebSocket,还需要普通 HTTP 接口吗?

通常需要。登录、历史记录查询、文件上传等明确的请求—响应操作仍适合普通 HTTP;WebSocket 主要承载实时事件。把所有接口强行塞进一条长连接,会增加协议设计、错误处理和调试成本。

从一道题,走向一组知识

把知识连起来

请求与通信 API

SSE 的 text/event-stream 数据格式长什么样,EventSource 如何接收消息?

继续看 EventSource 如何连接,以及 event、data、id 和 retry 字段怎样组成事件流。

请求与通信 API

设计 WebSocket 客户端的重连与心跳机制时需要考虑哪些要点?

选择 WebSocket 后,还需要处理心跳、断线检测和指数退避重连。

请求与通信 API

高频发送 WebSocket 消息时为什么需要关注 bufferedAmount,如何处理发送背压?

高频发送消息时,继续理解发送速度超过网络速度会发生什么。

参考资料

  • MDN · Using server-sent events
  • MDN · WebSocket API
  • WHATWG HTML · Server-sent events

示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。

本题目录
  1. 先记住这个答案
  2. 先问三个问题,就能完成大部分选型
  3. 两者真正有决定性的差异
  4. 用代码看懂 SSE:浏览器只负责接收
  5. 用代码看懂 WebSocket:同一连接既收又发
  6. 放进真实业务里,会更容易理解
  7. 选完协议,还要补上的边界
  8. 容易答错的地方
  9. 面试官还会怎么问
  10. 把知识连起来
读懂,再试着讲出来

先看核心答案,再读代码。最后展开追问,检查自己有没有遗漏边界。

试着回答追问
浏览全部面试题理解原理,也关注真实的使用场景。回到顶部 ↑