HTTP的演进

  • 为何现代的 AI 对话产品,能实现流畅的「打字机」效果?

  • 好像大家不再热衷谈论域名分片,文件打包等传输优化方案了

答案就在HTTP通信协议的演讲,继而洞察技术迭代背后的性能追求与架构思想

HTTP 演进的动力:追求极致的 Web 性能

这是一部不断追求更快,更具交互性的历史。从静态文本到富媒体、单页应用、实时通信,传输协议势必也须跟上脚步。这又是一场与延迟与带宽限制的战争。

HTTP1.0
1996
HTTP1.1
1999
HTTP2
2015
HTTP3
2022
核心问题 重建连接效率低,开销大 队头阻塞 TCP 层面的队头阻塞 UDP 部署挑战
CPU 开销
底层协议 TCP TCP TCP UDP(QUIC)
连接模型 每次 TCP 握手连接 短连接/持久连接 单一 TCP 连接 单一 QUIC 连接
数据传输 文本格式 文本格式 二进制分帧 二进制分帧
并发 N/A 顺序请求
管道机制受代理服务器实现限制
多路复用 多路复用
头部压缩 无(重复发送大量文本) 无(重复发送大量文本) HPACK
动态字典和霍夫曼编码压缩
QHPACK
安全性 N/A
HTTPS可选 不强制
但主流浏览器只支持 HTTPS
强制加密
(TLS1.3 内嵌)
连接建立 TCP 三次握手 TCP 三次握手+TLS 握手(2-3RTTs) TCP 三次握手+TLS 握手(2-3RTTs) 0-RTT/1-RTT 连接建立
连接迁移 N/A 不支持(IP/端口变动则连接中断) 不支持(IP/端口变动则连接中断) 支持(Connection ID),但部署仍面临 NAT 挑战
服务器推送 N/A 无(需 WebSocket 等) Server Push(已被主流浏览器废弃) 被废弃
流量控制 基于 TCP 滑动窗口 基于 TCP 滑动窗口 基于 Stream 和 Connection 的流量控制 基于 Stream 和 Connection 的流量控制

当时 HTTPS 为 Netscape基于 HTTP1.0+SSL 开发,但在 HTTP1.0 时代还不是标准的一部分,是一种扩展实现,标准支持在 1.1 时代正式确立。

HTTP1.1的变通智慧 VS HTTP2的反模式

通常浏览器对同一个域名限制 6 个 TCP 连接,所以大家就研发了一些妥协变通的前端黑科技,目的聚焦于突破并发限制和减少 HTTP 请求数,这些在新时代又变成反模式

HTTP1.1 HTTP2
域名分片 多个子域名,突破浏览器限制 徒增加额外的 DNS 查询和 TCP 连接开销
文件打包 多个 css 和 js 文件合并成一个,减少 HTTP 请求数 精细的代码分割更有利
雪碧图(CSS Sprites) 多个小图标合成一张大图,通过background-position 来显示,减少图片请求 同上
内联 将小 CSS 和 JS或图片(Base64)直接嵌入 HTML 中,减少 HTTP 请求数 同上

HTTP2 时代,优化策略从请求合并转向了按需、精细化地加载。由于底层协议解决了并发传输的瓶颈,使得上层应用可灵活组织和交付资源,拿到更好的缓存效率和首屏性能。

一个巨大的文件,哪怕只改了一行代码,用户也需重新下载整个文件,无法利用浏览器缓存。一个大 JS文件的任何阻塞,都会影响整个应用的渲染。

例外:弱网或高丢包率环境下,TCP 的队头阻塞可能被放大,这时HTTP1.1 的多域名优化策略仍然凑效。

HTTP2虽先进,但优势是建立在相对稳定的网络上的,所以要关注用户监控数据,判断客户端网络质量,动态决定是否回退 HTTP1.1 的多连接模式。

HTTP3-拥抱 UDP与挑战

QUIC(Quick UDP Internet Connections)基于 UDP在用户空间实现高效、可靠、安全的传输。但其用户空间的实现也意味着不如内核态高效,会更多的消耗 CPU 资源。

但部署有其挑战,来自全链路设备生态,老旧防火墙可能限制 UCP 流量,这时需回退至HTTP2 或 HTTP1.1。大型 CDN 服务是启用 HTTP3 的最现实和最高效方式,它们处理了协议协商,回退策略和全球网络优化等复杂问题,比自行部署优化更省力。

Web 通信的模式演进

  1. 请求-响应模型
  2. 轮询:客户端为获取实时数据,不停问,有新数据么…,效率低,浪费资源
  3. 长轮询:客户端问一次,服务端直到有数据再回答。减少了无效请求,但连接管理复杂
  4. WebSocket:全双工 TCP 连接,功能强大但协议复杂,还需自设计,有时会遇到网络设备(代理、防火墙)阻碍

如果我只需要服务端向客户端单向推送数据,不想 WebSocket 这么复杂,有没有办法?

  1. SSE:一个不断开的 HTTP 连接,服务端响应 Content-Type:text/event-stream,告知浏览器接下来的不是一个完整的数据块,请按事件流方式解析它。每个事件由若干文本行组成,以两个换行符(br/)结束。数据流由严格又简单的文本格式构成。

    1. data:<message> 是事件的数据内容一次可以有多行 data,它们会被拼接起来
    2. event:<event_name> (可选) 事件的类型。如果没有指定,客户端会监听到默认的 message 事件,客户端也可以监听不同类型的事件
    3. id:<unique_id> (可选) 事件的唯一ID。如果连接中断,浏览器会自动重新连接,并通过 HTTP Header Last-Event-ID 将这个 ID 发送给服务器,方便服务器从上次中断的地方继续发送。这是 SSE 自带断线重连机制的关键
    4. retry:<milliseconds> (可选) 告诉浏览器在断线后应该等待多少毫秒再尝试重连
  2. Streamable HTTP:利用 HTTP/1.1 中的Transfer-Encoding:chunked 特性及 HTTP2 的原生流支持。相较于 SSE 只能是固定格式的文本,Streamable HTTP可传任意数据(JSON,HTML 片段或二进制数据),并由前端自定义解析逻辑。

    分块格式:当前 chunk 大小(十六进制表示),后跟\r<br />; chunk 的数据内容,后跟\r<br />。最后一个数据,会发送一个大小为 0 的块,表示结束 0\r<br />\r<br />

WebSocket SSE-更上层 Streamable HTTP-更底层通用
特征 全双工,应用协议(ws/wss)独立于 HTTP,仅握手阶段依赖 HTTP
,用于高频双向通信
自带事件机制、自动重连、专注推送事件场景 给你原始数据块(Unit8Array),你拥有完全控制权
可解析任何自定义流式格式
断线重连 需手动实现(包括心跳保活) 原生支持(Last-Event-ID) 需手动实现
兼容性 可能会被旧防火墙阻挡 就是 HTTP 就是 HTTP
适用场景 聊天室、在线游戏、协同编辑(在线画板) 实时通知、状态更新、日志流 大文件流式渲染、AI 对话、自定义协议

需注意中间网络设备的超时调整和负载均衡粘性设定!

AI-MCP世代

MCP以 SSE 为基础,在早期版本实现了一种混合模式,解决双向通信问题,避免引入更复杂双向协议的开销。

SSE开发成本低,流式交互友好,长连接与自动重连开箱即用

  • 客户端先通过 SSE 订阅服务端推送(生成式长文本,如代码生成、多步推理过程展示)
  • 服务端会指示客户端通过一个专用 HTTP端点(如/message) 发送后续消息

SSE不足

  • Last-Event-ID 无法支撑复杂的用户态会话状态
  • 服务器维持 SSE 长连接的开销和故障迁移问题
  • 简单的请求,也必须以 SSE 返回消息,徒增负担
  • 负载均衡和网关可能未对长效 SSE 做兼容处理

Streamable HTTP

  • 统一端点,移除专用的/sse 端点,所有通信都通过单个端点进行(如/message),简化协议层设计和客户端配置
  • 普通 HTTP 响应和 SSE 流均灵活由服务端支持,友好于简单云函数
  • 会话标识与无状态服务支持
    • 引入 Mcp-Session-Id,识别统一会话的多次交互
    • 方便服务端可设计成无状态的

##参考