在实时通信成为前端高频需求的今天(聊天应用、AI 流式输出、实时通知等),WebSocket 和 SSE(Server-Sent Events)几乎是面试中的必考点。
这篇文章不仅帮你理解两者的本质区别,还会结合实际项目(如聊天系统、LLM 流式输出)讲清楚什么时候该用谁,以及面试该怎么讲。
一、为什么需要 WebSocket / SSE?
我们先从 HTTP 说起。
HTTP 是一种请求-响应模型:
- 客户端发起请求
- 服务端返回响应
- 连接结束(短连接)
问题在于:
如果服务端有“新数据”,无法主动推送给客户端。
比如:
- 聊天应用:别人发消息了
- 股票行情:价格变化
- AI 输出:模型逐字返回内容
如果继续用 HTTP,只能这样做:
1. 轮询(Polling)
setInterval(() => {
fetch('/messages')
}, 2000)
问题:
- 延迟高(取决于轮询间隔)
- 浪费资源(大量无效请求)
- 服务端压力大
这就是 WebSocket 和 SSE 出现的背景。
二、WebSocket:真正的双向实时通信
2.1 什么是 WebSocket?
WebSocket 是 HTML5 提供的一种协议:
在浏览器和服务器之间建立一个持久化的双向通信通道。
关键点:
- 基于 TCP
- 全双工通信(双向)
- 一次连接,持续通信
2.2 建立连接过程
WebSocket 并不是一开始就是 ws 协议,而是:
- 先通过 HTTP 发起请求
- 服务端返回:
101 Switching Protocols
- 协议升级为 WebSocket
这一步叫:协议升级(Upgrade)
2.3 通信特点
- 客户端可以主动发
- 服务端可以主动推
- 支持文本 / 二进制
const ws = new WebSocket('ws://localhost:3000/ws')
ws.onmessage = (event) => {
console.log(event.data)
}
ws.send('hello')
2.4 适用场景
WebSocket 适用于:
- 聊天系统(IM)
- 在线游戏
- 实时协作(文档编辑)
- 多人同步场景
因为这些场景都需要:
客户端和服务端都能随时发消息
三、SSE:为“服务端推送”而生
3.1 什么是 SSE?
SSE(Server-Sent Events)是基于 HTTP 的一种技术:
服务端可以持续不断地向客户端推送数据。
特点:
- 单向通信(只能服务端 → 客户端)
- 基于 HTTP
- 使用
text/event-stream
3.2 使用方式
前端:
const eventSource = new EventSource('/api/stream')
etSource.onmessage = (event) => {
console.log(event.data)
}
后端:
res.setHeader('Content-Type', 'text/event-stream')
res.write('data: hello\n\n')
3.3 核心特点
- 长连接(不会关闭)
- 自动重连
- 轻量级
- 仅支持文本(通常 JSON)
3.4 适用场景
SSE 非常适合:
AI 流式输出
比如 ChatGPT:
- 用户发送一次 prompt
- 服务端不断返回 token
完全符合:
一次请求 + 多次返回(单向流)
四、WebSocket vs SSE 核心区别
可以从 5 个维度对比(面试直接用):
4.1 通信方式
- HTTP / SSE:单向
- WebSocket:双向
这是最核心区别
4.2 协议
- SSE:基于 HTTP(text/event-stream)
- WebSocket:独立协议(ws / wss)
4.3 数据格式
- SSE:文本
- WebSocket:文本 + 二进制
4.4 使用复杂度
- SSE:简单
- WebSocket:复杂(连接管理、状态维护)
4.5 典型场景
| 技术 | 场景 |
|---|---|
| WebSocket | 聊天、游戏、协作 |
| SSE | AI 流式输出、通知 |
五、为什么聊天用 WebSocket,而不是 SSE?
这是一个面试“加分问题”。
聊天的本质需求:
- 用户要发消息(客户端 → 服务端)
- 用户要收消息(服务端 → 客户端)
是双向通信。
而 SSE:
- 只能服务端推送
- 客户端发消息仍需 HTTP
结果:
会变成:SSE + HTTP 混合方案(复杂且低效)
所以聊天必须用 WebSocket。
六、心跳机制
6.1 为什么需要?
因为 WebSocket / SSE 都是长连接:
可能出现:
- 网络断开
- 客户端掉线
- 连接假死
必须检测连接是否还活着。
6.2 实现原理
核心三步:
1️⃣ 定时发送 ping
setInterval(() => {
ws.send(JSON.stringify({ type: 'ping' }))
}, 30000)
2️⃣ 服务端返回 pong
if (msg.type === 'ping') {
ws.send(JSON.stringify({ type: 'pong' }))
}
3️⃣ 超时重连
- 如果没收到 pong
- 认为连接断开
- 触发重连逻辑
6.3 类比理解
可以这样说:
就像两个人打电话,会 periodically 问一句“你还在吗?”
七、HTTP vs WebSocket vs SSE 总结
| 特性 | HTTP | SSE | WebSocket |
|---|---|---|---|
| 通信方式 | 单向 | 单向 | 双向 |
| 连接 | 短连接 | 长连接 | 长连接 |
| 实时性 | 差 | 好 | 非常好 |
| 数据格式 | 任意 | 文本 | 文本/二进制 |
| 场景 | 普通请求 | 流式输出 | 实时通信 |
八、面试标准回答模板
如果面试官问:WebSocket 和 SSE 有什么区别?
你可以这样回答:
WebSocket 和 SSE 都可以实现服务端向客户端的实时推送,但两者有本质区别。
第一,通信方式不同:WebSocket 是全双工通信,客户端和服务端都可以主动发送消息;而 SSE 是单向通信,只能由服务端向客户端推送。
第二,协议不同:WebSocket 是独立协议,通过 HTTP Upgrade 升级;而 SSE 本质上还是 HTTP,使用 text/event-stream。
第三,使用场景不同:WebSocket 更适合聊天、游戏这类需要双向通信的场景;而 SSE 更适合像 AI 流式输出这种“请求一次,持续返回”的场景。
在实际项目中,我在做聊天系统时使用 WebSocket 来实现消息的实时收发和广播,而在对接大模型接口时使用 SSE 来实现流式输出,这样可以降低实现复杂度。
九、总结
一句话总结:
WebSocket 解决“实时双向通信”,SSE 解决“服务端持续推送”。
如果你是在做:
- 聊天系统 → WebSocket
- AI 输出 → SSE
基本不会选错。