SSE 与 WebSocket 新手入门:前端实时通信完全指南【JavaScript】

目录

  • 一、先说结论
  • [二、为什么 SSE 和 WebSocket 容易搞混?](#二、为什么 SSE 和 WebSocket 容易搞混?)
  • [三、什么是 HTTP?](#三、什么是 HTTP?)
  • [四、普通 HTTP 是什么样的?](#四、普通 HTTP 是什么样的?)
  • 五、什么是"长连接"?
  • [六、什么是 SSE?](#六、什么是 SSE?)
  • [七、SSE 是怎么工作的?](#七、SSE 是怎么工作的?)
  • [八、SSE 的通信过程](#八、SSE 的通信过程)
  • [九、SSE 为什么特别适合 AI?](#九、SSE 为什么特别适合 AI?)
  • [十、AI 流式输出](#十、AI 流式输出)
  • [十一、SSE 的前端实现](#十一、SSE 的前端实现)
  • [十二、EventSource 有什么限制?](#十二、EventSource 有什么限制?)
  • [十三、什么是 @microsoft/fetch-event-source?](#十三、什么是 @microsoft/fetch-event-source?)
  • [十四、SSE 和 AbortController](#十四、SSE 和 AbortController)
  • [十五、什么是 WebSocket?](#十五、什么是 WebSocket?)
  • [十六、WebSocket 像什么?](#十六、WebSocket 像什么?)
  • [十七、WebSocket 前端怎么使用?](#十七、WebSocket 前端怎么使用?)
  • [十八、WebSocket 最大的特点](#十八、WebSocket 最大的特点)
  • [十九、SSE 和 WebSocket 对比](#十九、SSE 和 WebSocket 对比)
  • [二十、SSE 和 WebSocket 的核心区别](#二十、SSE 和 WebSocket 的核心区别)
  • [二十一、SSE 适合什么场景?](#二十一、SSE 适合什么场景?)
    • [1. AI 流式输出](#1. AI 流式输出)
    • [2. 任务进度](#2. 任务进度)
    • [3. 实时日志](#3. 实时日志)
    • [4. 消息通知](#4. 消息通知)
  • [二十二、WebSocket 适合什么场景?](#二十二、WebSocket 适合什么场景?)
    • [1. 在线聊天](#1. 在线聊天)
    • [2. 在线游戏](#2. 在线游戏)
    • [3. 多人协作](#3. 多人协作)
    • [4. 实时控制](#4. 实时控制)
  • [二十三、为什么 AI 不全部使用 WebSocket?](#二十三、为什么 AI 不全部使用 WebSocket?)
  • [二十四、普通 HTTP、SSE、WebSocket 放在一起](#二十四、普通 HTTP、SSE、WebSocket 放在一起)
  • [二十五、还有一个容易混淆的东西:HTTP Streaming](#二十五、还有一个容易混淆的东西:HTTP Streaming)
  • [二十六、HTTP Streaming 和 SSE 有什么关系?](#二十六、HTTP Streaming 和 SSE 有什么关系?)
  • 二十七、前端应该怎么选择?
  • 二十八、一个非常实用的判断方法
  • 二十九、最终记忆图
  • 三十、一句话总结

一、先说结论

如果暂时不想看全文,可以先记住这张图:

text 复制代码
客户端 Client                          服务器 Server
    │                                      │
    │                                      │
    │──────────── 普通 HTTP ────────────→  │
    │←──────────── 返回结果 ──────────────  │
    │                                      │
    │              请求结束                 │

普通 HTTP:

请求一次,服务器回答一次。


SSE:

text 复制代码
客户端 Client                        服务器 Server
    │                                    │
    │──────────── 建立连接 ─────────────→ │
    │                                    │
    │←──────────── 数据 1 ────────────────│
    │←──────────── 数据 2 ────────────────│
    │←──────────── 数据 3 ────────────────│
    │←──────────── 数据 4 ────────────────│
    │                                    │

SSE:

客户端发起一次请求,服务器可以持续向客户端推送数据。

也就是:

text 复制代码
Server → Client

单向通信。


WebSocket:

text 复制代码
客户端 Client                        服务器 Server
    │                                   │
    │──────────── 建立连接 ─────────────→│
    │                                   │
    │──────────── 消息 ─────────────────→│
    │←─────────── 消息 ──────────────────│
    │──────────── 消息 ─────────────────→│
    │←─────────── 消息 ──────────────────│
    │──────────── 消息 ─────────────────→│
    │                                   │

WebSocket:

客户端和服务器双方都可以随时发送消息。

也就是:

text 复制代码
Client ↔ Server

双向通信。


二、为什么 SSE 和 WebSocket 容易搞混?

因为它们都有一个共同特点:

连接可以持续存在。

例如普通 HTTP:

text 复制代码
请求
 ↓
服务器处理
 ↓
返回
 ↓
结束

而 SSE:

text 复制代码
请求
 ↓
连接保持
 ↓
服务器不断发送数据
 ↓
连接结束

WebSocket:

text 复制代码
建立连接
 ↓
保持连接
 ↓
客户端 ↔ 服务器
 ↓
客户端 ↔ 服务器
 ↓
客户端 ↔ 服务器
 ↓
连接关闭

所以很多人会说:

SSE 和 WebSocket 都是长连接。

真正重要的是:

text 复制代码
SSE:(单向)

Server ─────────→ Client


WebSocket:(双向)

Server ←────────→ Client

三、什么是 HTTP?

在理解 SSE 和 WebSocket 之前,先理解 HTTP。

HTTP 可以简单理解成:

客户端和服务器之间进行通信的一套规则。

例如:

text 复制代码
浏览器
  │
  │ 请求
  ↓
服务器
  │
  │ 响应
  ↓
浏览器

前端:

js 复制代码
fetch('/api/user')

服务器可能返回:

json 复制代码
{
  "name": "张三",
  "age": 20
}

四、普通 HTTP 是什么样的?

比如我们有一个:

text 复制代码
GET /api/user

整个过程:

text 复制代码
Client
  │
  │ GET /api/user
  ↓
Server
  │
  │ 查询用户
  ↓
Server
  │
  │ 返回 JSON
  ↓
Client

然后这次请求就结束了。

所以普通 HTTP 可以简单理解成:

text 复制代码
请求一次
    ↓
响应一次
    ↓
结束

这特别适合:

text 复制代码
查询用户
创建订单
修改用户信息
删除数据
查询列表
提交表单

也就是我们平常说的:

CRUD 接口。


五、什么是"长连接"?

这里开始进入重点。

所谓长连接,可以简单理解为:

连接建立之后,不急着关闭,而是保持一段时间。

普通请求:

text 复制代码
请求
 ↓
响应
 ↓
结束

长连接:

text 复制代码
请求
 ↓
连接保持
 ↓
持续通信
 ↓
最后才关闭

注意:

长连接只是描述"连接保持比较久",并不等于某一种具体技术。

SSE 和 WebSocket 都可以实现持续通信,但是实现方式不同。


六、什么是 SSE?

SSE 全称:

text 复制代码
Server-Sent Events

中文通常叫:

服务器发送事件

SSE 是一种让服务器可以持续向浏览器推送数据的技术。

核心特点:

text 复制代码
Server → Client

也就是说:

服务器可以不断给客户端发送数据。


七、SSE 是怎么工作的?

假设前端请求:

text 复制代码
/api/chat

服务器不会马上结束响应,而是告诉浏览器:

http 复制代码
Content-Type: text/event-stream

意思是:

"这是一个持续的数据流。"

然后服务器可以不断发送:

text 复制代码
data: Hello

data: World

data: JavaScript

data: SSE

注意:

SSE 的消息之间通常通过空行进行分隔。


八、SSE 的通信过程

例如:

text 复制代码
浏览器                         服务器
  │                            │
  │────── 请求 /api/chat ──────→│
  │                             │
  │←──── data: Hello ───────────│
  │                             │
  │←──── data: World ───────────│
  │                             │
  │←──── data: SSE ─────────────│
  │                             │
  │←──── data: End ─────────────│
  │                             │

可以发现:

客户端主要负责:

text 复制代码
"听"

服务器负责:

text 复制代码
"不断说"

所以 SSE 特别适合:

服务器不断向客户端推送数据的场景。


九、SSE 为什么特别适合 AI?

你现在看到的很多 AI 产品:

text 复制代码
ChatGPT
Claude
各种 AI 编程助手
AI 搜索
AI 对话产品

回答的时候都有一个特点:

不是一次性把答案全部返回,而是一点一点生成。

例如:

text 复制代码
用户:

解释一下 JavaScript 闭包

服务器可能生成:

text 复制代码
闭包

然后:

text 复制代码
闭包是

然后:

text 复制代码
闭包是 JavaScript

然后:

text 复制代码
闭包是 JavaScript 中一种重要的机制

最后:

text 复制代码
闭包是 JavaScript 中一种重要的机制,它允许...

十、AI 流式输出

整个过程可以理解成:

text 复制代码
用户
 │
 │ "解释一下闭包"
 ↓
AI服务器
 │
 ├── "闭包"
 │
 ├── "是"
 │
 ├── "JavaScript"
 │
 ├── "中的"
 │
 ├── "一种"
 │
 └── "机制"
 ↓
浏览器

前端不断把收到的数据拼接起来:

js 复制代码
answer.value += event.data

于是用户看到:

text 复制代码
闭包

变成:

text 复制代码
闭包是

变成:

text 复制代码
闭包是 JavaScript

最终:

text 复制代码
闭包是 JavaScript 中的一种机制...

这就是我们经常看到的:

AI 打字机效果。


十一、SSE 的前端实现

浏览器原生提供了:

js 复制代码
EventSource

最简单的例子:

js 复制代码
const eventSource = new EventSource('/api/message')

eventSource.onmessage = (event) => {
  console.log(event.data)
}

服务器:

text 复制代码
data: Hello

data: World

前端:

js 复制代码
eventSource.onmessage = (event) => {
  console.log(event.data)
}

得到:

text 复制代码
Hello
World

十二、EventSource 有什么限制?

虽然 EventSource 很方便,但是它有一些限制。

例如:

js 复制代码
new EventSource('/api/message')

主要就是 GET 请求。

但是现在很多 AI 接口可能需要:

text 复制代码
POST
Authorization
请求体
自定义 Header
AbortController

例如:

js 复制代码
POST /api/chat

Authorization: Bearer xxx

{
  "message": "你好"
}

这时候原生 EventSource 就不太方便。


十三、什么是 @microsoft/fetch-event-source?

text 复制代码
@microsoft/fetch-event-source

它可以理解成:

一个基于 fetch 思路处理 SSE 的工具库。

安装:

bash 复制代码
pnpm add @microsoft/fetch-event-source

使用:

js 复制代码
import { fetchEventSource } from '@microsoft/fetch-event-source'

await fetchEventSource('/api/chat', {
  method: 'POST',

  headers: {
    'Content-Type': 'application/json'
  },

  body: JSON.stringify({
    message: '你好'
  }),

  onmessage(event) {
    console.log(event.data)
  }
})

这样就可以更方便地:

text 复制代码
POST
Header
Body
Signal
SSE

一起使用。

一键跳转 ➡️ microsoft/fetch-event-source 新手入门!超详细!!【SSE】【JavaScript库】


十四、SSE 和 AbortController

AI 对话还有一个非常常见的需求:

点击停止生成。

例如:

text 复制代码
AI:

JavaScript 是一种...
          ↓
        停止

这时候可以使用:

js 复制代码
const controller = new AbortController()

然后:

js 复制代码
fetchEventSource('/api/chat', {
  signal: controller.signal,

  onmessage(event) {
    console.log(event.data)
  }
})

用户点击停止:

js 复制代码
controller.abort()

于是:

text 复制代码
客户端
   │
   │ abort()
   ↓
停止 SSE 请求

这就是你之前学习的:

text 复制代码
AbortController

和 SSE 联系起来了。


十五、什么是 WebSocket?

WebSocket 是另一种实时通信技术。

它最大的特点:

客户端和服务器都可以主动发送消息。

也就是:

text 复制代码
Client ↔ Server

十六、WebSocket 像什么?

可以把 WebSocket 想象成:

打电话。

电话接通:

text 复制代码
你 ↔ 对方

你可以说话:

text 复制代码
你 → 对方

对方也可以主动说话:

text 复制代码
你 ← 对方

而且不需要每次都重新打电话。

WebSocket 就很像这种模式。


十七、WebSocket 前端怎么使用?

浏览器原生提供:

js 复制代码
WebSocket

例如:

js 复制代码
const ws = new WebSocket('wss://example.com/chat')
javascript 复制代码
wss://example.com/chat
│      │           │
│      │           └── WebSocket 路径(API路径)
│      └───────────────── 服务器域名
└──────────────────────── WebSocket 安全协议
协议 含义 类似
ws:// 普通 WebSocket http://
wss:// 加密 WebSocket https://
javascript 复制代码
const ws = new WebSocket(
  'wss://www.xxx.com/ws'
)

连接成功:

js 复制代码
ws.onopen = () => {
  console.log('连接成功')
}

收到服务器消息:

js 复制代码
ws.onmessage = (event) => {
  console.log(event.data)
}

客户端主动发送:

js 复制代码
ws.send('你好')

连接关闭:

js 复制代码
ws.onclose = () => {
  console.log('连接关闭')
}

发生错误:

js 复制代码
ws.onerror = (error) => {
  console.error(error)
}

十八、WebSocket 最大的特点

注意这个:

js 复制代码
ws.send('你好')

客户端可以主动发送消息。

服务器也可以主动发送:

text 复制代码
Server → Client

因此:

text 复制代码
SSE:

Client ─────────→ Server
          请求
Client ←───────── Server
          数据

主要是单向推送


WebSocket:

Client ─────────→ Server
Client ←───────── Server
Client ─────────→ Server
Client ←───────── Server

双向通信

十九、SSE 和 WebSocket 对比

这是最重要的一张表。

对比 SSE WebSocket
全称 Server-Sent Events WebSocket
通信方向 单向 双向
Server → Client
Client → Server ❌*
长连接
基于 HTTP WebSocket 协议
浏览器 API EventSource WebSocket
数据特点 事件流 双向消息
AI 流式输出 ⭐⭐⭐⭐⭐ ⭐⭐⭐
在线聊天 ⭐⭐⭐ ⭐⭐⭐⭐⭐
在线游戏 ⭐⭐⭐⭐⭐
多人协作 ⭐⭐ ⭐⭐⭐⭐⭐
实现难度 较简单 相对复杂

❌* 指的是 SSE 的同一条事件流不是用来做客户端持续双向发送的;客户端当然可以另外通过普通 HTTP 请求向服务器发送数据。


二十、SSE 和 WebSocket 的核心区别

如果面试官问:

SSE 和 WebSocket 有什么区别?

你可以回答:

SSE 是基于 HTTP 的服务器推送技术,主要用于服务器向客户端持续发送数据,是单向通信;WebSocket 是一种双向通信协议,客户端和服务器都可以主动发送消息,更适合实时聊天、在线游戏、多人协作等双向实时场景。

然后补充:

text 复制代码
SSE:

Server → Client


WebSocket:

Server ↔ Client

基本就已经抓住核心了。


二十一、SSE 适合什么场景?

1. AI 流式输出

text 复制代码
AI回答
 ↓
一个字/一段一段返回

非常典型。


2. 任务进度

例如:

text 复制代码
任务开始

0%
 ↓
20%
 ↓
40%
 ↓
60%
 ↓
80%
 ↓
100%

服务器不断通知前端:

text 复制代码
进度:20%
进度:40%
进度:60%
进度:80%
进度:100%

非常适合 SSE。


3. 实时日志

例如部署系统:

text 复制代码
开始构建...

安装依赖...

编译中...

构建成功...

部署完成...

服务器不断把日志推给前端。


4. 消息通知

例如:

text 复制代码
你有一条新消息

服务器可以主动推送给浏览器。


二十二、WebSocket 适合什么场景?

1. 在线聊天

例如:

text 复制代码
用户 A ↔ 服务器 ↔ 用户 B

双方都可能主动发送消息。


2. 在线游戏

例如:

text 复制代码
玩家移动
 ↓
客户端 → 服务器
 ↓
服务器 → 其他玩家

而且这种通信频率可能非常高。


3. 多人协作

例如在线编辑文档:

text 复制代码
A 修改内容
 ↓
服务器
 ↓
B、C、D

同时:

text 复制代码
B 修改内容
 ↓
服务器
 ↓
A、C、D

这是典型的双向实时通信。


4. 实时控制

例如:

text 复制代码
客户端
   ↓
控制服务器
   ↓
设备

设备状态
   ↓
服务器
   ↓
客户端

双方都需要通信。


二十三、为什么 AI 不全部使用 WebSocket?

这是一个很好的问题。

因为很多 AI 对话其实是:

text 复制代码
用户
 ↓
发送问题

AI
 ↓
不断生成答案
 ↓
不断发送给用户

也就是:

text 复制代码
Client → Server

Server → Client
Server → Client
Server → Client
Server → Client

实际上主要是:

text 复制代码
服务器 → 客户端

所以 SSE 非常合适。

没必要为了:

text 复制代码
Server ↔ Client

的能力引入 WebSocket。


二十四、普通 HTTP、SSE、WebSocket 放在一起

现在把三个放在一起:

text 复制代码
                网络通信
                    │
        ┌───────────┼───────────┐
        ↓           ↓           ↓
      HTTP         SSE       WebSocket
        │           │           │
     请求/响应    服务端推送    双向通信
        │           │           │
        ↓           ↓           ↓
      CRUD      AI流式输出      聊天
                任务进度        游戏
                实时日志        协作

二十五、还有一个容易混淆的东西:HTTP Streaming

除了 SSE 和 WebSocket,还有:

HTTP Streaming

这个概念也非常重要。

HTTP Streaming 可以简单理解成:

服务器通过 HTTP 响应持续发送数据,客户端边接收边处理。

例如:

text 复制代码
HTTP Response
 ↓
数据块1
 ↓
数据块2
 ↓
数据块3
 ↓
数据块4

前端可以使用:

js 复制代码
fetch('/api/stream')

然后读取:

js 复制代码
const response = await fetch('/api/stream')

const reader = response.body.getReader()

while (true) {
  const { done, value } = await reader.read()

  if (done) {
    break
  }

  console.log(value)
}

二十六、HTTP Streaming 和 SSE 有什么关系?

这个地方非常重要:

SSE 是一种特定格式的 HTTP 流。

可以简单理解成:

text 复制代码
HTTP Streaming
     │
     ├── 普通数据流
     │
     └── SSE
           │
           └── text/event-stream

SSE 有自己规定的数据格式:

text 复制代码
data: Hello

data: World

而普通 HTTP Streaming 可以是任意数据块。

所以:

text 复制代码
HTTP Streaming

是一个更大的概念。

而:

text 复制代码
SSE

是其中一种具体实现方式。


二十七、前端应该怎么选择?

以后遇到需求,可以按照下面的方式判断。

场景一:普通 API

text 复制代码
查询用户
查询列表
创建订单
修改数据

使用:

text 复制代码
fetch / axios

场景二:服务器不断给我数据

例如:

text 复制代码
AI回答
任务进度
实时日志

优先考虑:

text 复制代码
SSE

场景三:客户端和服务器都需要实时发送

例如:

text 复制代码
在线聊天
实时游戏
多人协作
实时控制

考虑:

text 复制代码
WebSocket

二十八、一个非常实用的判断方法

以后看到需求,直接问自己一个问题:

"谁需要主动说话?"

只有服务器需要不断说话

text 复制代码
Server → Client

考虑:

text 复制代码
SSE

客户端和服务器都需要不断说话

text 复制代码
Client ↔ Server

考虑:

text 复制代码
WebSocket

只是问一次答一次

text 复制代码
Client → Server
Server → Client

考虑:

text 复制代码
HTTP

二十九、最终记忆图

把这张图记住:

text 复制代码
                    前端网络通信
                         │
        ┌────────────────┼────────────────┐
        │                │                │
        ↓                ↓                ↓
      HTTP              SSE          WebSocket
        │                │                │
        │                │                │
   请求一次          持续推送          双向通信
        │                │                │
        ↓                ↓                ↓
    Client → Server   Server → Client   Client ↔ Server
        │                │                │
        ↓                ↓                ↓
      CRUD           AI流式输出         在线聊天
                     任务进度           在线游戏
                     实时日志           多人协作

三十、一句话总结

最后只记住这三个:

text 复制代码
普通 HTTP:

"我问你一次,你回答我一次。"
text 复制代码
SSE:

"我问你一次,你可以一直告诉我后续发生了什么。"
text 复制代码
WebSocket:

"我们俩建立一条长期通道,谁想说话都可以随时说。"

用程序员的话来说:

text 复制代码
HTTP
Client → Server → Client

SSE
Client → Server
Server → Client → Client → Client → Client

WebSocket
Client ↔ Server
Client ↔ Server
Client ↔ Server

所以最核心的区别不是"谁是长连接",而是"通信方向和使用场景不同"。

相关推荐
艾伦野鸽ggg1 小时前
25级开学 JS 考核题解
前端·javascript
meilindehuzi_a1 小时前
LangChain.js + Milvus 向量长期记忆实战:对话写入、语义检索与 RAG 增强
javascript·langchain·milvus
leoZ2311 小时前
2026-09-08-mysql-57-init-walkthrough
前端·javascript·数据库·vue.js·opencv·mysql·adb
艾伦野鸽ggg1 小时前
JavaScript 原型链与原型对象详解
javascript·原型模式
paopaokaka_luck1 小时前
非遗文物数字化系统(AI非遗问答、ONNX图像识别、协同过滤推荐、ECharts数据分析、非遗知识浏览与互动、文创商城订单闭环、文化活动报名签到、社区交流)
前端·javascript·vue.js·人工智能·数据分析·echarts
乘风gg2 小时前
AI Coding 提效 2 倍是真的吗?到底怎么衡量效果
前端·ai编程·claude
用户921080262862 小时前
从对象到原型链:理解 this、构造函数和 new
前端
猫不易2 小时前
Webpack 与 Vite:从 Loader / Plugin 到 Rolldown 统一引擎
前端·vite
YHL2 小时前
🎯 Danci —— 用 AI 驱动开发一个全栈英语单词学习平台
前端·后端