一、 HTTP 长连接 (Persistent Connections / Keep-Alive)
1. 历史背景
在早期的 HTTP/1.0 时代,HTTP 请求采用的是短连接 模式。浏览器每请求一个资源(哪怕是一张几十 KB 的小图片),都需要经历:建立 TCP 连接(三次握手) →\rightarrow→ 发送 HTTP 请求 →\rightarrow→ 接收 HTTP 响应 →\rightarrow→ 断开 TCP 连接(四次挥手)。
随着 Web 页面变得复杂,包含大量的图片、CSS 和 JS 脚本,这种"用完即弃"的连接方式导致了极大的网络开销和延迟。网络的大部分时间都浪费在了建立和断开底层的 TCP 连接上。
2. 核心机制
为了解决这个问题,HTTP/1.1 将**长连接(Keep-Alive)**设为了默认标准。
- 在请求头和响应头中包含
Connection: keep-alive。 - 一次 TCP 连接建立后,可以传输多个 HTTP 请求和响应。
- 只要客户端和服务器在设定好的超时时间内(Timeout)没有主动断开,或者没有达到最大请求数(MaxRequests),底层的 TCP 连接就会一直保持开放状态,供后续的 HTTP 请求复用。
3. 应用场景
- 现代所有的常规 Web 浏览。
- 内部微服务调用(复用连接池以降低延迟)。
二、 流式 HTTP (Streamable HTTP / Chunked Transfer Encoding)
1. 历史背景
在 HTTP 协议的原始设计中,接收端需要知道自己何时接收完了一个完整的响应报文。通常的做法是通过响应头中的 Content-Length 字段来声明数据的总字节数。
但这带来了一个问题:如果服务器生成数据的速度很慢,或者数据量极其巨大(甚至是无限的),服务器在开始发送数据前根本无法计算出总长度。 如果必须等待所有数据生成完毕再计算 Content-Length,会导致极高的首字节延迟(TTFB)和极大的内存占用。
2. 核心机制
HTTP/1.1 引入了分块传输编码(Chunked Transfer Encoding)。
- 服务器在响应头中设置
Transfer-Encoding: chunked,并省略Content-Length。 - 数据被分割成一系列的"数据块"(Chunks)。每一个数据块都包含一个十六进制的长度标识和一个数据体。
- 接收端边接收边处理,直到收到一个长度为
0的特殊数据块,即表示整个响应传输结束。 - 注意: 流式 HTTP 必须依赖底层的 HTTP 长连接,否则连接断开就无法继续传输后续的块了。
3. 应用场景
- 大文件下载。
- 动态生成内容的页面返回。
- 流媒体视频的初步加载。
- 作为后续 SSE 技术的底层传输基石。
三、 Server-Sent Events (SSE)
1. 历史背景
长连接解决了"连接复用"问题,流式 HTTP 解决了"长度未知"问题,但传统的 HTTP 依然受制于一个根本原则:客户端不发起请求,服务器就不能主动发送数据。
在很多业务中(如股票报价、实时新闻),我们需要服务器将最新数据"推送"给客户端。早期的做法是客户端轮询(Polling,定时发请求问有没有新数据),这非常浪费资源。后来出现了 WebSocket,实现了全双工的双向通信,但对于只需要服务器单向推送的场景来说,WebSocket 过于重型且协议复杂。SSE 应运而生,并在 HTML5 中被标准化。
2. 核心机制
SSE 建立在 HTTP 长连接和流式 HTTP 的基础之上,但在应用层进行了更高阶的封装。
- 客户端通过 JavaScript 的
EventSourceAPI 发起一个普通的 HTTP GET 请求。 - 服务器响应头声明
Content-Type: text/event-stream,并保持连接不关闭(利用 Keep-Alive 和 Chunked 机制)。 - 服务器按照特定的纯文本格式(如
data: 你的消息内容\n\n)持续不断地向客户端推送事件流。 - 浏览器原生地支持 SSE 并在底层处理断线重连(自带
Last-Event-ID机制以恢复丢失的消息)。
3. 应用场景
- 大语言模型(如 ChatGPT、Claude)的打字机效果输出(最典型的现代应用)。
- 实时的股票或加密货币价格 ticker。
- 社交媒体的实时消息通知、新闻滚动播报。
- CI/CD 部署流水线的实时日志展示。
四、 总结与对比分析
以下是这三者在维度和目的上的根本区别:
| 维度 | HTTP 长连接 (Keep-Alive) | 流式 HTTP (Chunked) | Server-Sent Events (SSE) |
|---|---|---|---|
| 解决的核心问题 | 减少 TCP 握手/挥手开销,提高传输效率。 | 解决无法提前预知响应体大小、需逐步下发数据的问题。 | 解决服务器向客户端进行轻量级、实时、单向推送的问题。 |
| 工作层面 | TCP 连接管理策略。 | HTTP 报文的编码与封装方式。 | 基于 HTTP 协议构建的浏览器 API 与应用层数据格式标准。 |
| 通信方向 | 请求-响应机制本身不变。 | 请求-响应机制本身不变。 | 服务器 -> 客户端单向推送。 |
| 技术依赖关系 | 基础基石。 | 依赖于长连接不被中断。 | 必须依赖长连接,通常结合流式 HTTP 使用。 |
| 响应标识 | Connection: keep-alive |
Transfer-Encoding: chunked |
Content-Type: text/event-stream |