当前位置: 首页 > news >正文

HTTP 1.0, 2.0 和 3.0 有什么区别?

HTTP/1.0 就像是“一问一答”的电话,每次打电话(请求)都得先拨号(建立连接),说完一句话(发送数据)就挂断(关闭连接),再打下一通电话。效率比较低。

HTTP/2.0 就像是“多路复用”的电话会议,一次拨号(建立连接)后,大家可以在同一个会议室里同时说多句话(多路复用),而且还可以压缩语言(头部压缩),甚至会议主持人(服务器)可以提前把大家可能需要的文件准备好(服务器推送)。这样效率就高多了。

为什么需要 HTTP?

在理解 HTTP/1.0 和 HTTP/2.0 的区别之前,我们得先明白 HTTP 协议本身是干嘛的。

想象一下,互联网就像一个巨大的图书馆。你(客户端)想从图书馆里借一本书(资源),图书馆管理员(服务器)需要知道你要哪本书,然后把书给你。HTTP(HyperText Transfer Protocol,超文本传输协议)就是你和图书馆管理员之间交流的“语言”或“规矩”。它规定了你如何提出请求,管理员如何回应,以及数据如何传输。

核心目标: 让客户端和服务器能够高效、可靠地交换信息(主要是网页、图片、视频等资源)。

从 1.0 到 2.0

HTTP/1.0:初期的“一问一答”模式

HTTP/1.0 是互联网早期设计的协议,它非常简单直接,就像我们上面说的“一问一答”的电话。

核心思想: 每次请求-响应都建立一个新的 TCP 连接,完成后立即关闭。

  1. 用户需求: 我要一个网页。
  2. 网页构成: 一个网页通常不只包含 HTML 文本,还有图片、CSS 文件、JavaScript 文件等等。
  3. 1.0 的做法:
    • 客户端请求 HTML 文件。
    • 服务器响应 HTML 文件。
    • 连接关闭。
    • 客户端解析 HTML,发现还需要图片 A。
    • 客户端再次建立 TCP 连接,请求图片 A。
    • 服务器响应图片 A。
    • 连接关闭。
    • …以此类推,直到所有资源都加载完毕。

这种模式有什么缺点?

  • 连接建立/关闭开销大: 每次建立 TCP 连接都需要“三次握手”,关闭需要“四次挥手”,这就像每次打电话都要先拨号、等待接通、再挂断,非常耗时。
  • 队头阻塞(Head-of-Line Blocking): 即使你有很多请求要发,也必须等前一个请求的响应完全回来,才能发送下一个请求。这就像你在排队买票,前面的人没买完,你就不能买。
  • 带宽利用率低: 连接频繁建立和关闭,导致网络带宽无法持续高效利用。

流程图:HTTP/1.0 请求流程

客户端
请求 HTML
建立 TCP 连接
发送 HTTP 请求 (HTML)
服务器处理
发送 HTTP 响应 (HTML)
关闭 TCP 连接
客户端解析 HTML
发现需要图片1
建立 TCP 连接
发送 HTTP 请求 (图片1)
服务器处理
发送 HTTP 响应 (图片1)
关闭 TCP 连接
重复上述过程
直到所有资源加载完毕
HTTP/1.1:小修小补,引入持久连接

HTTP/1.1 在 1.0 的基础上做了一些改进,最核心的就是引入了持久连接(Persistent Connections),也叫 Keep-Alive

默认情况下,一个 TCP 连接在发送完一个请求-响应后不会立即关闭,而是保持一段时间,允许在这个连接上发送后续的请求。

  1. 1.0 的痛点: 频繁建立/关闭连接。
  2. 如何优化? 既然一个网页需要多个资源,那能不能只建立一次连接,然后在这个连接上把所有资源都请求完再关闭呢?
  3. 1.1 的做法:
    • 客户端请求 HTML 文件。
    • 建立 TCP 连接。
    • 发送 HTTP 请求 (HTML)。
    • 服务器响应 HTML。
    • 连接保持开放。
    • 客户端解析 HTML,发现需要图片 A。
    • 在同一个 TCP 连接上,发送 HTTP 请求 (图片 A)。
    • 服务器响应图片 A。
    • 连接保持开放。
    • …直到所有资源都加载完毕,或者达到超时时间,连接才关闭。

1.1 解决了连接建立/关闭的开销,但还有什么问题?

  • 队头阻塞依然存在: 虽然连接是持久的,但请求和响应仍然是串行的。你必须等前一个请求的响应完全回来,才能发送下一个请求。这就像你和朋友打电话,虽然没挂断,但你们还是得轮流说话,不能同时说。
  • 头部冗余: 每次请求都会发送大量的重复头部信息(如 User-Agent, Accept 等),浪费带宽。
  • 没有服务器推送: 服务器只能被动响应,不能主动推送客户端可能需要的资源。

流程图:HTTP/1.1 请求流程 (持久连接)

客户端
请求 HTML
建立 TCP 连接
发送 HTTP 请求 (HTML)
服务器处理
发送 HTTP 响应 (HTML)
客户端解析 HTML
发现需要图片1
在同一连接上
发送 HTTP 请求 (图片1)
服务器处理
发送 HTTP 响应 (图片1)
重复上述过程
直到所有资源加载完毕
或连接超时
关闭 TCP 连接
HTTP/2.0:彻底的性能革命

随着网页越来越复杂,资源越来越多,HTTP/1.1 的队头阻塞问题变得越来越突出。人们开始思考,有没有一种方式,能让一个连接同时处理多个请求和响应,就像多车道高速公路一样?这就是 HTTP/2.0 的核心思想。

HTTP/2.0 基于 Google 的 SPDY 协议,它在应用层和传输层之间增加了一个二进制分帧层

  1. 多路复用(Multiplexing): 在一个 TCP 连接上,同时发送多个请求和接收多个响应,且请求和响应之间互不影响。

  2. 二进制分帧(Binary Framing): 所有通信都被分解为更小的、独立的帧,并以二进制格式传输。

  3. 头部压缩(Header Compression): 使用 HPACK 算法压缩 HTTP 头部,减少冗余数据传输。

  4. 服务器推送(Server Push): 服务器可以在客户端请求某个资源时,主动推送客户端可能需要的其他资源。

  5. 请求优先级(Request Prioritization): 客户端可以为请求设置优先级,服务器可以根据优先级决定响应顺序。

  6. 1.1 的痛点: 队头阻塞,头部冗余,无服务器推送。

  7. 如何解决队头阻塞?

    • 多路复用: 把每个请求和响应都拆分成小块(帧),给每个帧一个唯一的标识符。然后这些帧可以在同一个 TCP 连接上乱序发送,接收方根据标识符再重新组装。这就像快递公司,把你的包裹拆成小件,然后和别人的小件一起装车,到了目的地再根据单号重新组装。
    • 二进制分帧: 为什么是二进制?因为二进制解析效率高,更紧凑,不像文本协议那样需要复杂的解析。
  8. 如何解决头部冗余?

    • 头部压缩: 很多请求的头部信息是重复的,比如 User-Agent。我们可以维护一个“字典”(索引表),把常用的头部信息存起来,下次只发送字典的索引号就行了。
  9. 如何提高加载速度?

    • 服务器推送: 客户端请求 HTML 页面时,服务器知道这个页面肯定需要 CSS 和 JS 文件,那服务器就可以在客户端还没请求 CSS 和 JS 之前,就把它们“推”给客户端。这样客户端就不用再发请求了,节省了往返时间。
  10. 如何优化资源加载顺序?

    • 请求优先级: 客户端可以告诉服务器,哪个资源更重要(比如 CSS 比图片更重要),服务器就可以优先处理重要的请求。

流程图:HTTP/2.0 请求流程

客户端
建立 TCP 连接 (一次)
多路复用层
请求 HTML (流1)
请求 图片1 (流2)
请求 CSS1 (流3)
请求 JS1 (流4)
二进制分帧
头部压缩
二进制分帧
头部压缩
二进制分帧
头部压缩
二进制分帧
头部压缩
所有帧在同一TCP连接上
乱序发送
服务器接收帧
重新组装
服务器处理 HTML (流1)
服务器处理 图片1 (流2)
服务器处理 CSS1 (流3)
服务器处理 JS1 (流4)
服务器推送
(例如: 发现HTML需要CSS2, JS2)
发送 CSS2 (流5)
发送 JS2 (流6)
所有响应帧在同一TCP连接上
乱序发送
客户端接收帧
重新组装
客户端解析并渲染页面
连接保持开放
直到所有通信结束

核心本质

  • HTTP/1.0: 简单粗暴,每次任务独立完成。它的本质是串行处理,资源利用率低。
  • HTTP/1.1: 在 1.0 基础上打了个补丁,通过持久连接减少了连接开销,但本质上还是串行请求-响应,只是在同一个管道里串行。
  • HTTP/2.0: 彻底改变了传输方式,引入了多路复用。它的本质是并行处理,通过在应用层和传输层之间增加一个“调度层”(二进制分帧层),将逻辑上的多个流映射到物理上的一个 TCP 连接,从而解决了队头阻塞,并引入了更多优化手段。它不再是简单的“一问一答”,而是更像一个智能的“数据管道”。

继续思考

  • 为什么不直接在 TCP 层解决队头阻塞? TCP 层的队头阻塞是数据包丢失重传导致的。如果一个 TCP 包丢失了,即使后面的包都收到了,TCP 也必须等待丢失的包重传成功并按序组装,才能把数据交给应用层。HTTP/2.0 的多路复用是在应用层实现的,它解决了 HTTP 层面(逻辑流)的队头阻塞,但无法解决 TCP 层面(物理包)的队头阻塞。这也是为什么 HTTP/3.0 转向 UDP (QUIC) 的原因之一,因为它想从传输层彻底解决队头阻塞。
  • HTTP/2.0 的安全性: 虽然 HTTP/2.0 协议本身不强制加密,但几乎所有主流浏览器都只支持基于 TLS/SSL 的 HTTP/2.0 (即 HTTPS)。这使得 HTTP/2.0 在实践中比 HTTP/1.x 更安全。
  • HTTP/2.0 的适用场景: 对于需要加载大量小文件、或者需要频繁与服务器交互的单页应用 (SPA) 等场景,HTTP/2.0 的性能优势尤为明显。

队头阻塞的本质是:在需要保证顺序性的系统中,如果“队头”的元素处理受阻,那么“队尾”的元素即使已经准备好,也无法越过队头被处理。

TCP 队头阻塞是为了保证数据包的可靠性和按序交付。如果一个数据包丢失,后续的数据包即使到达,也无法被应用层消费,因为 TCP 无法确定后续数据包的完整上下文。

HTTP/1.x 队头阻塞是因为 HTTP/1.x 协议设计上,在单个 TCP 连接中,请求和响应是严格串行且一一对应的。它没有机制来区分和并行处理不同的逻辑流。

流程图:HTTP/2.0 多路复用与流

客户端
建立单个 TCP 连接
HTTP/2.0 二进制分帧层
创建流1: 请求图片A
创建流2: 请求CSS文件
创建流3: 请求JS文件
图片A帧1 (流1)
图片A帧2 (流1)
CSS帧1 (流2)
JS帧1 (流3)
所有帧在TCP连接上
交错发送 (乱序)
服务器
接收交错帧
HTTP/2.0 二进制分帧层
根据流ID重组帧
重组流1: 完整图片A请求
重组流2: 完整CSS请求
重组流3: 完整JS请求
服务器处理请求
(并行处理)
生成流1响应帧
生成流2响应帧
生成流3响应帧
所有响应帧在TCP连接上
交错发送 (乱序)
客户端
接收交错帧
HTTP/2.0 二进制分帧层
根据流ID重组帧
交付应用层: 图片A响应
交付应用层: CSS响应
交付应用层: JS响应
O1,O2,O3
F,L

为什么 HTTP/2.0 能解决 HTTP 层的队头阻塞?

HTTP/2.0 引入了多路复用。它把每个 HTTP 请求和响应都看作一个独立的“流”(Stream),每个流都有自己的 ID。这些流的数据被拆分成更小的“帧”,这些帧可以在同一个 TCP 连接上乱序发送。接收方根据帧的 ID 重新组装成完整的流。HTTP/2.0 解决了应用层(HTTP 协议层面)的队头阻塞,因为它不再强制请求和响应的串行顺序。

HTTP/2.0 为什么不能解决 TCP 层的队头阻塞?

HTTP/2.0 仍然是基于 TCP 协议的。如果底层的 TCP 连接中,某个数据包丢失了,那么整个 TCP 连接仍然会因为等待这个丢失的数据包重传而暂停,这会影响到所有在当前 TCP 连接上跑的 HTTP/2.0 流。这就像电话会议(HTTP/2.0)开得很好,但如果电话线(TCP 连接)断了,所有人都受影响。

HTTP/3.0 如何解决 TCP 层的队头阻塞?

HTTP/3.0 放弃了 TCP,转而使用基于 UDP 的 QUIC 协议。QUIC 协议在传输层实现了自己的可靠传输和多路复用机制。它为每个逻辑流分配独立的序列号,这样即使一个流的数据包丢失,也只会影响到这一个流,而不会阻塞其他流的数据传输。这就像,你和朋友们在不同的房间里打电话,即使一个房间的电话线断了,其他房间的通话也不受影响。

特性HTTP/1.0HTTP/2.0
连接管理短连接:每个请求-响应建立新 TCP 连接,完成后立即关闭。长连接/多路复用:一个 TCP 连接可同时处理多个请求和响应。
请求方式串行请求:必须等待前一个响应完成后才能发送下一个请求。并行请求:多个请求可同时发送,响应可乱序返回。
队头阻塞存在:HTTP 层面和 TCP 层面都存在。解决 HTTP 层面:通过多路复用解决。TCP 层面仍可能存在。
数据传输文本协议:基于文本,解析相对复杂。二进制分帧:所有数据分解为二进制帧传输,解析高效。
头部处理无压缩:每次请求发送完整且重复的头部信息。头部压缩 (HPACK):压缩头部,减少冗余数据。
服务器推送不支持:服务器只能被动响应。支持:服务器可主动推送客户端可能需要的资源。
请求优先级不支持支持:客户端可设置请求优先级。
安全性通常不加密 (HTTP)多数实现强制加密 (HTTPS)
性能较低,尤其在加载大量资源时。显著提高,尤其在加载大量资源时。

HTTP/2.0 是对 HTTP/1.x 的一次彻底的性能优化 对于HTTP/1.x,在服务器处理某个请求资源回复慢时,会阻塞其他请求,而2.0使用流的逻辑标识,可以同时发不同的请求,尽管带宽是一样的,却可以降低延迟,更高效率的利用网络传输通道,它将TCP的流组合成不同的请求数据,解决了应用层的队头阻塞,可是依旧是基于TCP流的,这意味,由于网络层面的TCP出错依旧会队头阻塞,并没有解决本质问题

而3.0彻底解决了这个问题,3.0不再使用TCP而是UDP,每个请求都是额外的流,QUIC协议可以将传输和加密的握手结合在一起,如果客户端之前连接过服务器,并且服务器支持,甚至可以实现 0-RTT 握手,即客户端在发送第一个数据包时就包含应用数据,几乎没有延迟。 TCP 连接是基于 IP 地址和端口号的。如果你的设备从 Wi-Fi 切换到移动数据(IP 地址变化),TCP 连接就会断开,需要重新建立。 QUIC 连接是基于一个 64 位的连接 ID。即使客户端的 IP 地址或端口号发生变化,只要连接 ID 不变,QUIC 连接就可以保持活跃,无需重新建立。

流程图:HTTP/3.0 (QUIC) 解决队头阻塞

客户端
服务器
HTTP 应用层
(Web 服务器)
HTTP/3.0 (QUIC) 层
HTTP/3.0 (QUIC) 层
HTTP 应用层
(浏览器)
创建 QUIC 流1: 请求图片A
创建 QUIC 流2: 请求CSS文件
创建 QUIC 流3: 请求JS文件
流1数据包
(独立序列号)
流2数据包
(独立序列号)
流3数据包
(独立序列号)
所有流的数据包
在单个UDP连接上
并行传输
服务器接收流1数据包
(独立处理重传)
服务器接收流2数据包
(独立处理重传)
服务器接收流3数据包
(独立处理重传)
处理请求1
处理请求2
处理请求3
响应1 (流1)
响应2 (流2)
响应3 (流3)
所有流的响应数据包
在单个UDP连接上
并行传输
客户端接收流1数据包
(独立处理重传)
客户端接收流2数据包
(独立处理重传)
客户端接收流3数据包
(独立处理重传)
交付应用层: 响应1
交付应用层: 响应2
交付应用层: 响应3
A,G
K1,K2,K3
E,I
D1,D2,D3,F1,F2,F3,H1,H2,H3,J1,J2,J3

UDP本身并不会有失败重发的机制,所以即使是一个UDP连接网络抖动不会影响整个UDP连接的数据重发,而是在QUIC协议负责每个流的重发,QUIC实现都是在应用层的,也因此对操作系统内核没有额外要求,不需要更改,把TCP的可靠性实现由操作系统内核上升到应用层去实现这些

http://www.xdnf.cn/news/1310635.html

相关文章:

  • OpenAI TTS API + Web 前端 AudioContext 实战方案
  • (论文速读)ViDAR:视觉自动驾驶预训练框架
  • leetcode-139. 单词拆分-C
  • 中本聪思想与Web3的困境:从理论到现实的跨越
  • 从依赖到自研:一个客服系统NLP能力的跃迁之路
  • 昇腾AI自学Day2-- 深度学习基础工具与数学
  • Spring AI 进阶之路01:三步将 AI 整合进 Spring Boot
  • 异构数据库兼容力测评:KingbaseES 与 MySQL 的语法・功能・性能全场景验证解析
  • linux设备驱动之字符设备驱动
  • Python代码规范与静态检查(ruff/black/mypy + pyproject.toml + Makefile)自动化工具链介绍
  • 【LeetCode 热题 100】70. 爬楼梯——(解法二)自底向上
  • 在鸿蒙应用中快速接入地图功能:从配置到实战案例全解析
  • ISO27001 高阶架构 之 支持 -2
  • PHP域名授权系统网站源码/授权管理工单系统/精美UI/附教程
  • 广东省省考备考(第七十八天8.16)——资料分析、判断推理(强化训练)
  • Spring AMQP如何通过配置文件避免硬编码实现解耦
  • Linux -- 文件【下】
  • 深度解析和鲸社区热门项目:电商双 11 美妆数据分析的细节与价值
  • 41 C++ STL模板库10-容器3-list
  • 正点原子【第四期】Linux之驱动开发篇学习笔记-1.1 Linux驱动开发与裸机开发的区别
  • docker-compose-mysql-定时备份数据库到其他服务器脚本
  • 【机器学习深度学习】OpenCompass:支持的开源评估数据集及使用差异
  • RemoteCtrl-初步的网络编程框架搭建
  • 安全审计-firewall防火墙
  • 算法训练营day52 图论③ 101.孤岛的总面积、102.沉没孤岛、103.水流问题、104.建造最大岛屿
  • 基于Uni-app+vue3实现微信小程序地图固定中心点范围内拖拽选择位置功能(分步骤详解)
  • MySQL 配置性能优化赛技术文章
  • 基于Python3.10.6与jieba库的中文分词模型接口在Windows Server 2022上的实现与部署教程
  • Flutter开发 网络请求
  • ESP32-S3_ES8311音频输出使用