模块一:引言
HTTP(HyperText Transfer Protocol) 是基于 TCP/IP 的应用层协议,是互联网数据通信和网页传输的基石。
它采用请求-响应模式,是无状态协议,特别适合海量用户的高 并发访问场景。
HTTP 是一种请求-响应模式的协议:客户端发起请求,服务器返回响应。过程非常 简单,却极其强大——正是这种简洁性,让 HTTP 得以快速普及,成为互联网的"通用语言"。
同时,它也是无状态协议——服务器不会记得你上一次请求说了什么。每次请求都是 独立的。这种设计让它能够轻松应对海量并发访问,但也催生了 Session、Cookie、Token 等会话管理机制。
从 1991 年 HTTP 0.9 诞生至今,经历了多次重大升级。本文 将从历史演进的角度,带你系统回顾 HTTP 协议的发展脉络。
模块二:HTTP 0.9 和 HTTP 1.0 — 协议的诞生与初探
HTTP 0.9(1991年)— 一切的开始
1991年,万维网(World Wide Web)的发明者 Tim Berners-Lee 发布了 HTTP
的第一个版本。
这是一个极其简单的协议,只有一行命令:
GET /index.html
服务器直接返回 HTML 文档内容,传输完成就断开连接。
它的特点:
- 仅支持 GET 方法
- 无请求头、无响应头
- 只能传输纯 HTML 文本
- 每次请求都是一个新的 TCP 连接
现在的眼光看,HTTP 0.9 简陋得难以置信。但正是这个简单的开始,开启了互联网时代的大门。
HTTP 1.0(1996年)— 走向标准化
随着互联网蓬勃发展,HTTP 0.9 已经不够用了。1996年,HTTP 1.0 正式发布,协议开始走向标准化。
1. 多种请求方法
HTTP 1.0 扩展了请求方法:
- GET — 从服务器读取资源
- POST — 向服务器提交数据
- HEAD — 仅获取响应头,不返回正文
POST 的出现意义重大——它让表单提交成为可能,Web 开始从"只读"走向"可写"。
2. 请求头(Headers)
HTTP 1.0 创新性地引入了请求头和响应头的概念,让客户端和服务器能够传递元数据。
常用请求头:
- User-Agent — 客户端信息,比如浏览器版本、操作系统
- Cookie — 会话标识,服务端下发的会话 ID
- Content-Type — 请求体格式,比如 application/json
- Accept — 可接受的响应类型,比如 text/html, */
- Authorization — 认证信息,比如 Bearer token 或 Basic auth
User-Agent 是其中最有意思的一个。它的格式大致如下:
Mozilla/5.0 (Macintosh; Intel Mac OS X 10\_15\_7)
AppleWebKit/537.36 (KHTML, like Gecko)
Chrome/146.0.0.0 Safari/537.36
这一串标识的意思是:
- Mozilla/5.0 最初是 Netscape 浏览器的标识,后来所有浏览器都兼容这个标识
- (Macintosh; Intel Mac OS X 10_15_7) 告诉你操作系统和硬件信息
- AppleWebKit/537.36 是渲染引擎
- Chrome/146.0.0.0 是浏览器版本号
- Safari/537.36 是为了兼容 Safari
这就是为什么国内早期要区分 PC 站和移动站——不同的 User-Agent 告诉服务器你用的是什么设备,服务器就返回不同的页面。
3. 短连接
HTTP 1.0 依然是短连接模式:每次请求都要先 TCP三次握手建立连接,请求完成后四次挥手断开连接,下一次请求再重新建连。
一个网页可能有几十个资源——HTML、CSS、JS、图片、字体……每个都要单独建立和断开 TCP 连接。这种方式在当时互联网规模还不大的时候勉强够用,但随着网页资源越来越多,性能问题开始凸显。
HTTP 1.0 为协议奠定了基本框架:确立了请求-响应模式,引入了 Headers
的概念,支持多种请求方法。 但它也有很多局限:短连接效率低、无状态导致会话管理困难、明文传输不安全…… 这些问题的解决方案,都留给了下一代的 HTTP 1.1。
模块三:HTTP 1.1 —— 经典的基石
HTTP 1.1 于 1997 年发布(RFC 2068,后经 RFC 2616 等修订),它解决了 HTTP 1.0 在高并发场景下的性能瓶颈,成为了互联网的中流砥柱,至今仍被广泛支持。
1. 持久连接(Keep-Alive)
这是 HTTP 1.1 最大的改进。在 HTTP 1.0 中,默认使用短连接(每次请求后断开 TCP 连接),导致网页加载大量资源时,频繁进行 TCP 三次握手和四次挥手,消耗巨大。
HTTP 1.1 默认启用长连接:
- 复用 TCP:一个 TCP 连接可以连续发送多个 HTTP 请求,不必每次请求都重新建连。
- 流水线(Pipeline) :理论上允许客户端连续发送多个请求,而不需要等待上一个响应回来(虽然因“队头阻塞”问题,浏览器实际大多未启用此功能,而是采用并发多个长连接的方式)。
2. 管道化(Pipelining)与队头阻塞(Head-of-Line Blocking)
文档中提到 HTTP 2.0 解决了“对头阻塞”,其根源就在于 HTTP 1.1 的局限性:
- 问题:虽然 HTTP 1.1 允许在同一个连接中发送多个请求,但为了保证数据顺序,服务器必须按顺序响应。如果第一个请求的响应很慢(比如一个大图片),后面的请求即使处理完了,也必须排队等待,这就造成了“队头阻塞”。
- 现状:为了解决这个问题,浏览器通常会对同一个域名开启 6-8 个并行的 TCP 连接,但这又增加了服务器压力。这也是后来 HTTP 2.0 引入“多路复用”的直接原因。
3. 缓存机制的增强
HTTP 1.1 引入了更精细化的缓存控制策略,减少了不必要的网络传输:
- 强缓存:
Cache-Control(如max-age),比 HTTP 1.0 的Expires更灵活。 - 协商缓存:
ETag/If-None-Match。相比 HTTP 1.0 的Last-Modified,ETag 可以更精确地判断资源是否被修改(例如文件修改时间相同但内容变了的情况)。
4. Host 头字段(虚拟主机)
在 HTTP 1.0 时代,服务器 IP 地址通常是一对一的。HTTP 1.1 引入了 Host 请求头,使得一台物理服务器可以托管多个网站(虚拟主机),极大地节省了 IP 地址资源。
模块四:HTTP 2.0 — 性能飞跃
HTTP 1.1 虽然大大提升了 Web的能力,但它的核心问题——对头阻塞——始终没有解决。
2015年,HTTP 2.0发布,专门针对这个痛点进行了底层重构。
1. 二进制分帧
HTTP 1.1 的数据是明文传输的,所有数据混在一起,没有边界,没有编号,想插队 是不可能的。
举个例子:
假设浏览器同时请求:
- 流 1:index.html
- 流 3:style.css
- 流 5:app.js
HTTP 2.0 的传输可能是这样的——帧交错在一起:
流1帧头 → 流3帧头 → 流1数据 → 流5帧头 → 流3数据 → 流1数据 → ...
到达接收端之后,按流 ID 分开重组:
流1:帧1-1 + 帧1-2 + 帧1-3 → 拼成 index.html
流3:帧3-1 + 帧3-2 → 拼成 style.css
流5:帧5-1 + 帧5-2 → 拼成 app.js
为什么能解决对头阻塞?
因为每个流都有自己的 ID,独立重组。假设流 1 的某个帧丢了,只影响流1,流3和流5 照样传输、照样重组,完全不受影响。
2. 多路复用
基于二进制分帧,HTTP 2.0 实现了真正的多路复用(Multiplexing):
- 一个 TCP 连接中可以并发多个请求
- 每个请求都有一个独立的流 ID
- 帧可以交错发送,按流 ID 归类重组
举个例子:
浏览器要请求 index.html、style.css、app.js 三个资源。
HTTP 1.1 时代:
同一个域名只能开 1-6 个 TCP
连接(浏览器限制),每个请求必须等上一个响应回来才能发下一个:
TCP连接1:GET /index.html → 等 → 收到响应 → GET /style.css → 等 →
收到响应 → GET /app.js ...
TCP连接2:GET /app.js → 等 → 收到响应
...
如果 index.html 卡住了,后面 style.css 和 app.js 只能在后面排队等。
HTTP 2.0 时代:
一个 TCP 连接就够了。三个请求分属三个流,同时发送:
一个 TCP 连接里:
→ 流1: GET /index.html
→ 流3: GET /style.css
→ 流5: GET /app.js
← 流1: 返回 index.html 数据帧
← 流3: 返回 style.css 数据帧
← 流5: 返回 app.js 数据帧
三个流并行跑,互不等待,互不阻塞。
这从根本上解决了 HTTP 1.1 的对头阻塞问题。
3. 服务器推送
传统的请求模式是:浏览器请求 HTML → 服务器返回 HTML → 浏览器解析 HTML
发现需要 CSS/JS → 再去请求 CSS/JS。
HTTP 2.0 支持服务器推送(Server Push):服务器知道浏览器需要什么资源,主动把 CSS/JS 推送给浏览器,浏览器还没请求就已经收到了。
这样就省去了浏览器反复请求的延迟。
4. 头部压缩
HTTP 2.0 还对 Header 进行了压缩。因为一个请求的 Header 往往有几百字节,而实际数据可能只有几字节,Header 的开销非常大。
HTTP 2.0 使用 HPACK 算法压缩 Header,进一步减少了传输量。
HTTP 2.0 的意义
HTTP 2.0 通过二进制分帧和多路复用,从根本上解决了 HTTP 1.1 的对头阻塞问题,让 Web 性能有了质的飞跃。
但它仍然有一个隐患——底层还是 TCP。TCP 在传输层也有对头阻塞问题,一旦丢包,整个 TCP 连接上的所有流都会受影响。
这个问题的最终解决方案,就是 HTTP 3.0。
模块五:HTTP 3.0 — QUIC 革命
HTTP 2.0 虽然解决了应用层的对头阻塞,但它的底层还是 TCP。TCP在传输层同样存在对头阻塞——一旦丢包,整个 TCP连接上的所有数据都要等待重传,所有流都被卡住。
HTTP 3.0 就是为了彻底解决这个问题。
HTTP 3.0 的核心是 QUIC(Quick UDP Internet Connections),一种基于 UDP的传输协议。
UDP 的特点是什么?无连接、不重传、不管顺序——简单粗暴,速度快,但不可靠。
QUIC
在 UDP 之上实现了自己的可靠传输逻辑,把 TCP 的优点移植过来,同时避免了
TCP 的缺点。
HTTP 3.0 的核心改进
1. 彻底抛弃 TCP,全程 UDP
HTTP 3.0 不再使用 TCP,而是直接基于 QUIC。没有 TCP 三次握手,改用 QUIC
自己的连接建立逻辑。
2. 每个流独立,不再互相影响
QUIC 把连接分成多个流(Stream)。丢包了?只影响当前流,其他流照常跑。这就 是真正的无对头阻塞。
3. 0-RTT 快速建立连接
第一次连接需要 1-RTT,之后可以做到 0-RTT——客户端直接发送数据,连接已经建立了。
4. 内置 TLS
HTTP 3.0 把加密直接做进了传输层,而不是像 HTTPS 那样单独跑一个 TLS
层。QUIC 本身就支持加密,而且比 TLS 更快。
一句话总结
HTTP 3.0 = HTTP 2.0 的所有特性 + QUIC(基于 UDP)= 彻底解决对头阻塞 +
更快建立连接 + 内置加密
模块六:总结
一部解决痛点的历史回顾 HTTP 的演进,有一条清晰的脉络:
HTTP 0.9 → HTTP 1.0 → HTTP 1.1 → HTTP 2.0 → HTTP 3.0
每一次升级,都是为了解决上一代暴露出来的核心问题。
-
HTTP 0.9 太简陋,只能发 GET 请求,于是 HTTP 1.0 加入了 POST、HEAD、请求头和响应头。
-
HTTP 1.0 每次请求都要重新建连,效率太低,于是 HTTP 1.1 引入了长连接,多个请求可以复用同一个 TCP 连接。
-
HTTP 1.1 的管道化听起来很美,但响应没有编号,一个请求卡住后面全部排队,实际被浏览器弃用。
-
HTTP 2.0 用二进制分帧和流 ID 彻底解决了这个问题,一个 TCP 连接里可以并发多个请求,互不阻塞。
HTTP 2.0 看起来很完美了,但底层还是 TCP。TCP本身的传输层对头阻塞没有解决,一旦丢包,所有流都受影响。
- HTTP 3.0 直接抛弃TCP,改用基于 UDP 的 QUIC,每个流独立可靠传输,彻底告别了对头阻塞。
各版本一句话定位
- HTTP 0.9:一行 GET,一切的开端
- HTTP 1.0:引入 Header,走向标准化
- HTTP 1.1:长连接为主,但应用层对头阻塞无法根治
- HTTP 2.0:二进制分帧 + 多路复用,从根本上解决对头阻塞
- HTTP 3.0:基于 QUIC(UDP),彻底解决对头阻塞,更快、更安全