Stream HTTP、SSE流式、websocket原理是什么

下面详细解释 Stream HTTP(通常指 HTTP 分块传输 / 原始流)、SSE(Server-Sent Events) 以及 WebSocket 的原理与区别。


一、原理说明

1. Stream HTTP(基于 HTTP 1.1 分块传输)

  • 本质:利用 HTTP 1.1 的 Transfer-Encoding: chunked,服务器在响应头不提供 Content-Length,而是将数据分成多个小块(chunk)逐步发送给客户端。

  • 工作流程

    1. 客户端发起普通 HTTP 请求。

    2. 服务器立刻返回 200 OKTransfer-Encoding: chunked 头。

    3. 服务器每生成一块数据,就按 chunk 格式(十六进制长度 + 数据 + CRLF)发送。

    4. 连接保持打开,直到服务器发送长度为 0 的 chunk 结束。

    5. 客户端需要自行解析 chunk 数据(浏览器的 fetch 或 XHR 可通过 response.body 流式读取)。

  • 通信方向:仅 服务器 → 客户端(单向)。

  • 特点:无标准客户端事件 API,无自动重连,需手动处理流解析。

2. SSE (Server-Sent Events)

  • 本质:HTML5 标准中的 服务器单向推送 规范,基于 HTTP 协议,MIME 类型为 text/event-stream

  • 工作流程

    1. 客户端使用 EventSource API 发起请求。

    2. 服务器保持长连接,并按照 data: xxx\n\n 格式发送消息(可附带 ideventretry 等字段)。

    3. 浏览器自动解析消息,触发 onmessage 或自定义事件。

    4. 若连接断开,浏览器会自动重连(根据 retry 字段间隔)。

  • 通信方向:仅 服务器 → 客户端(单向)。

  • 特点:内置重连、事件 ID、自动解析,支持 UTF-8 文本,非常轻量。

3. WebSocket

  • 本质:独立的 全双工 通信协议(RFC 6455),通过 HTTP 升级握手建立持久连接。

  • 工作流程

    1. 客户端发送 Upgrade: websocket 的 HTTP 请求。

    2. 服务器返回 101 Switching Protocols,完成协议升级。

    3. 后续通信使用 WebSocket 帧(文本/二进制),不再遵循 HTTP 语义。

    4. 客户端和服务器可以随时主动发送数据。

  • 通信方向:双向,同一连接上既可发送也可接收。

  • 特点:支持二进制数据、真正的全双工、低延迟,但实现相对复杂,需要专用服务端支持。


二、核心区别对比表

 
特性Stream HTTP (chunked)SSEWebSocket
协议基础 HTTP 1.1 HTTP 独立协议(通过 HTTP 升级)
通信方向 单向(服务器→客户端) 单向(服务器→客户端) 全双工(双向)
浏览器 API 无原生 API(需 fetch + 流处理) EventSource(标准、简单) WebSocket(标准、功能丰富)
自动重连 ❌ 无 ✅ 内置(可配置重连间隔) ❌ 需自己实现
消息格式 任意字节流(需自定义解析) UTF‑8 文本(支持自定义 event) 文本 或 二进制帧
数据量限制 无(分块传输) 无(但通常不适合超大二进制) 无(但受连接和内存限制)
头部开销 每个请求有 HTTP 头 一次请求,后续无额外头 握手后仅 2–14 字节帧头
服务器压力 每个连接消耗一个 HTTP 请求 长连接,类似 keep‑alive 持久连接,开销较低
防火墙友好性 ✅ 使用标准 80/443 端口 ✅ 使用标准 HTTP/HTTPS 端口 ✅ 通常走 80/443(但协议不同)
适用场景 文件下载、日志流、简单推送 实时股价、通知、服务器单向下发 聊天、游戏、协同编辑、双向通信

三、关键差异详解

1. 连接模型与重连机制

  • Stream HTTP:请求结束后连接关闭(或由服务器主动结束)。断线后需客户端重新发起请求,且无法恢复上次进度。

  • SSE:长连接,断开后 EventSource 自动重连,并可通过 Last-Event-ID 恢复丢失的消息(需要服务器配合)。

  • WebSocket:长连接,断开后需手动重连,且由于无内置消息 ID,恢复断流需应用层实现。

2. 数据方向与实时性

  • Stream HTTP & SSE:只能服务器发数据给客户端。如果客户端要发送数据,必须另起 HTTP 请求,造成额外开销。

  • WebSocket:双向同时收发,适合交互频繁的场景(如在线游戏)。

3. 浏览器支持与降级

  • Stream HTTP:所有支持 HTTP/1.1 的浏览器都能接收分块响应,但流式读取依赖 fetch + ReadableStream(现代浏览器)。

  • SSE:除 IE 和部分旧 Edge 外,所有现代浏览器均支持;可通过 polyfill 降级到长轮询。

  • WebSocket:所有现代浏览器支持;无法降级到 HTTP,但可使用轮询或 SSE 模拟(效率低)。

4. 消息边界

  • Stream HTTP:没有消息边界,需要自己定义分隔符(如换行、长度前缀)。

  • SSE:以 data: 行和双换行符 \n\n 作为消息边界,浏览器自动分割。

  • WebSocket:通过帧(frame)保证消息完整性,一个帧就是一个完整的消息(或分片组装)。

5. 二进制数据传输

  • Stream HTTP:可以传输二进制(chunk 本质是字节流)。

  • SSE:标准规定为 UTF-8 文本,传递二进制需要 base64 编码,浪费带宽。

  • WebSocket:原生支持二进制帧,高效直接。


四、选型建议

 
如果你的需求是…推荐技术
服务器单向发送大量文本更新,需要自动重连、简单可靠 SSE
实时双向通信,例如聊天、游戏、低延迟交互 WebSocket
仅需临时下载大文件或日志流,不需要重连或自定义解析 Stream HTTP
兼容老旧系统,或服务器不允许 WebSocket 协议 SSE 或长轮询
需要发送二进制帧(如音频、视频流) WebSocket

注意:实际开发中,SSE 和 WebSocket 经常结合使用 —— 例如用 WebSocket 做双向交互,用 SSE 做单向业务推送(避免 WebSocket 消息类型混乱)。而 Stream HTTP 更多作为底层实现细节,不推荐直接暴露给前端业务逻辑。


五、简单代码示例(概念)

Stream HTTP(前端流式读取)

javascript
const response = await fetch('/stream');
const reader = response.body.getReader();
while (true) {
  const { done, value } = await reader.read();
  if (done) break;
  console.log(new TextDecoder().decode(value));
}

SSE

javascript
const source = new EventSource('/events');
source.onmessage = (e) => console.log(e.data);
source.onerror = () => console.log('断开,自动重连');

WebSocket

javascript
const ws = new WebSocket('ws://example.com');
ws.onmessage = (e) => console.log(e.data);
ws.send('hello'); // 双向发送

如果有更具体的场景或技术细节需要深入探讨,欢迎继续提问!

 
posted @ 2026-06-06 17:09  飘来荡去evo  阅读(19)  评论(0)    收藏  举报