每当提到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>
  • 因为是人类可读的基于文本,所以调试很简单,

  • 通过 curltelnetnc 等工具大致了解结构。

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)

  • 更有效地使用网络资源

如果只提炼出核心关键词:

  1. 二进制帧(Binary Framing)

  2. 基于流的多路复用(Multiplexing)

  3. 头部压缩(HPACK)

  4. (原本) 服务器推送(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请求/响应头部的重复性相当高。

    • CookieUser-AgentAccept-*

    • 每个请求可能会包含数百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扩展来负责。

    • 客户端:“我支持 h2http/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作为默认选择。”

    这是合理的。

    但在实际工作中:

    1. 完全没有HTTP/1.1是很困难的

      • 老旧的客户端或特殊环境仍然只能使用1.1

      • 在调试/工具/内部系统等方面,总是使用1.1会更方便

    2. 从服务器的角度,“同时支持两者”是很常见的

      • 在Web服务器的设置中像这样开启h2 http/1.1

    3. 现在考虑HTTP/3(QUIC)的时代

      • 最新的浏览器/服务已经支持HTTP/3

      • 但这些通常也是同时开启“HTTP/1.1 + HTTP/2 + HTTP/3”,
        由客户端协商选择。

    因此,现实的结论是:

    “与其坚持只用HTTP/2,不如
    将HTTP/2作为默认启用,同时将HTTP/1.1作为自然的后备选项。”

    这是最佳选择。


    根据HTTP版本的传输方式比较

    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)处理。”