每当提到HTTP版本时,通常会有这样的想法。
“不管怎样,互联网不都是HTTP吗?1.1和2有什么不同呢?”
“反正都是新版本的HTTP/2,直接用不就行了?”
总结如下:
-
HTTP/1.1与HTTP/2的区别在于,二者并不是“完全不同的协议”,而是以更高效的方式传递相同的HTTP信息(方法/头/状态码等)。
-
在实际服务中,并不是“选择其中一个”,而是服务器同时支持两者,客户端根据情况选择其一的结构较为常见。
接下来我会从开发者的角度总结核心要点。
1. HTTP/1.1 简单总结
1) 基于文本的协议
HTTP/1.1是我们常见的这样的请求/响应格式。
GET /index.html HTTP/1.1
Host: example.com
Connection: keep-alive
HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 1234
<html>...</html>
-
因为是人类可读的基于文本,所以调试很简单,
-
通过
curl、telnet、nc等工具大致了解结构。
2) 持久连接 + 管道化
HTTP/1.0的一个主要问题是每个请求都要重新建立TCP连接,而在HTTP/1.1中,默认设置为持久连接(keep-alive),
可以在一个连接上顺序发送多个请求。
另外还有一个功能就是HTTP管道化:
-
在未等待响应的情况下连续发送请求
-
按顺序接收响应。
但在实际浏览器中几乎没有使用,
仍然存在“必须按顺序处理的结构”,因此性能问题仍然存在。
3) HOL(头部排队)阻塞问题
HTTP/1.1著名的瓶颈就是HOL(头部排队)阻塞。
-
由于在一个连接中请求必须顺序处理,
-
如果最前面的请求变慢,后面的请求也必须一起等待。
-
因此,浏览器为每个域(origin)打开多个TCP连接(例如:最多6个)来减轻这个问题。
总结一下:
HTTP/1.1是一种“通过创建多个管道来减小瓶颈的方式”。
(多个TCP连接)
2. HTTP/2有什么不同?
HTTP/2的目标很明确。
-
减少延迟(latency)
-
更有效地使用网络资源
如果只提炼出核心关键词:
-
二进制帧(Binary Framing)
-
基于流的多路复用(Multiplexing)
-
头部压缩(HPACK)
-
(原本) 服务器推送(Server Push) – 实际上在浏览器中已被淘汰
2-1. 从文本到二进制帧
HTTP/1.1是逐行文本解析,而在HTTP/2中,所有内容都通过帧(frame)这个二进制块进行传送。
-
头部是HEADERS帧
-
主体是DATA帧
-
这些帧属于特定的流ID。
开发者几乎不会直接接触帧,
但这使得我们可以实现多路复用、头部压缩和优先级等功能。
2-2. 多路复用(Multiplexing)
这是最直观的区别。
-
HTTP/1.1:在一个TCP连接上请求-响应顺序处理
-
HTTP/2:在一个TCP连接上同时推送多个流
也就是说,
“无需打开多个TCP连接,
而是将请求和响应组装在一个连接内同时发送”
这样,无论是在一个HTML页面需要获取数十到数百个资源时,
只需保持一个连接即可同时获取这些资源,
在移动环境或高RTT环境中尤其有利。
不过,仍然存在在TCP层面上HOL阻塞的问题,因此这一点也在HTTP/3(QUIC)中得到了进一步改善。
2-3. 头部压缩(HPACK)
HTTP请求/响应头部的重复性相当高。
-
Cookie、User-Agent、Accept-*等 -
每个请求可能会包含数百KB甚至数MB的数据
HTTP/2通过一种叫做HPACK的头部压缩方式,
减少了这些头部之间的重复。
-
常用的头部在表中注册,通过短索引发送
-
有效编码与上次请求不同的部分
因此,尤其在请求量大的SPA / 内容丰富的页面中获益颇丰。
2-4. 服务器推送(Server Push)实际上已死
在HTTP/2初期,曾被视为服务器在客户端请求之前推送CSS/JS等内容的服务器推送(Server Push)功能的一个重要优点,但在实际应用中:
-
实现难度高,
-
缓存/重复资源问题,
-
实际的性能提升微乎其微,甚至恶化的情况也有所发生。
因此,Chrome/Chromium系列自2022年起默认禁用了此功能(Chrome for Developers)
Firefox也计划在2024年去掉支持,因此在浏览器生态中,这一功能基本已经结束。
所以,至今我们谈论HTTP/2时,服务器推送仅可被视为“历史性的功能”。
3. HTTPS, ALPN,和“h2 vs http/1.1选择”
在实际服务中,“使用HTTP/1.1还是HTTP/2”是
客户端与服务器在TLS握手过程中自动协商的。
这由ALPN(应用层协议协商)这个TLS扩展来负责。
-
客户端:“我支持
h2,http/1.1两者” -
服务器:“那我们就用
h2吧”(或者“我只支持http/1.1”)
Apache示例设置:
Protocols h2 http/1.1
这样设置后:
-
支持HTTP/2的最新浏览器会自动使用HTTP/2(h2)
-
旧版客户端会自动使用HTTP/1.1进行通信
大多数主要浏览器已经很好地支持HTTP/2,
相当多的网站也已经启用了HTTP/2。
4. “在什么情况下分开使用?” – 开发者角度总结
我们来看看关键问题的不同情况。
4-1. 一般的网页服务(面向浏览器)
接近正确的策略:
“以HTTPS + HTTP/2作为默认开启,
将HTTP/1.1作为备用。”
-
绝大多数Web服务器(Nginx、Apache、Envoy等)和CDN只需开启HTTP/2支持选项,便会自动协商。
-
应用程序层面上,几乎没有必要像“这个请求用1.1,那个用2”这样手动分开。
也就是说,如果新建服务,可以默认考虑“开启HTTP/2的HTTPS”。
4-2. 内部API / 微服务通信
这里的选择更多。
-
如果已经用REST + HTTP/1.1运行得很好,
就不必重新编写为HTTP/2。 -
但如果,
-
同一服务之间频繁交换极短的请求,或
-
使用类似gRPC的HTTP/2基础协议,那么
→ 使用HTTP/2是比较自然的。
-
即,
-
“旧的遗留REST API” → 维持1.1 + 在需要时在代理/负载均衡器上进行HTTP/2终止
-
“新引入gRPC,高频调用微服务” → 积极利用HTTP/2
4-3. 调试、日志记录、遗留环境
HTTP/1.1在某些情况下依然非常有用。
-
基于文本,便于在tcpdump、Wireshark中查看内容
-
旧的代理/防火墙/客户端可能不支持HTTP/2
-
在一些简单的内部工具、测试服务器等场合,可以不使用HTTP/2也完全足够
实际上在很多环境中:
-
外部(浏览器)↔ 前端代理(CDN/负载均衡器) : 使用HTTP/2
-
代理 ↔ 后端服务 : 使用HTTP/1.1
混合结构的情况很多。
5. “就不能只用HTTP/2吗?”的现实回答
理论上:
“如果是新创建的公共Web服务,可以将HTTP/2作为默认选择。”
这是合理的。
但在实际工作中:
-
完全没有HTTP/1.1是很困难的
-
老旧的客户端或特殊环境仍然只能使用1.1
-
在调试/工具/内部系统等方面,总是使用1.1会更方便
-
-
从服务器的角度,“同时支持两者”是很常见的
-
在Web服务器的设置中像这样开启
h2 http/1.1,
-
-
现在考虑HTTP/3(QUIC)的时代
-
最新的浏览器/服务已经支持HTTP/3
-
但这些通常也是同时开启“HTTP/1.1 + HTTP/2 + HTTP/3”,
由客户端协商选择。
-
因此,现实的结论是:
“与其坚持只用HTTP/2,不如
将HTTP/2作为默认启用,同时将HTTP/1.1作为自然的后备选项。”
这是最佳选择。

6. 总结
-
HTTP/1.1
-
基于文本
-
持久连接 + (理论上的)管道化
-
由于HOL阻塞问题,浏览器多个TCP连接同时使用
-
-
HTTP/2
-
二进制帧
-
在一个TCP连接中同时处理多个流的多路复用
-
HPACK头部压缩
-
服务器推送在实践中已基本处于停用状态
-
-
使用策略
-
外部Web(面向浏览器):开启HTTPS + HTTP/2,并将HTTP/1.1作为备用
-
内部API:现有REST可维持1.1,频繁请求/流的情况下使用HTTP/2
-
调试/遗留:HTTP/1.1仍然方便且有用
-
开发者应牢记的一句话:
“在应用代码中不要纠结于版本的选择,
要将HTTP/2设置为开启,并将其他交给协议协商(ALPN)处理。”
目前没有评论。