本文内容摘自:

HTTP 协议主要的版本目前有 4 个,分别是 HTTP/1.0、HTTP/1.1 、HTTP/2 和 HTTP/3。

🥳 HTTP 版本 - 图1

HTTP/1.0

1996年 5 月,HTTP/1.0 版本发布,为了提高系统的效率,HTTP/1.0 规定浏览器与服务器只保持短暂的连接,浏览器的每次请求都需要与服务器建立一个 TCP 连接,服务器完成请求处理后立即断开 TCP 连接,服务器不跟踪每个客户也不记录过去的请求。

HTTP/1.1

为了解决 HTTP/1.0 存在的缺陷,HTTP/1.1 于 1997 年诞生。相比较于 HTTP/1.0 来说,最主要的改进就是引入了持久连接。所谓的持久连接就是:在一个 TCP 连接上可以传送多个 HTTP 请求和响应,减少了建立和关闭连接的消耗和延迟。

🥳 HTTP 版本 - 图2

这是目前使用范围最广的协议。

SPDY

虽然,HTTP/1.1 在 HTTP/1.0 的基础上提供了持久连接,提升了很大的效率,但是,还是有很大的提升空间。
正所谓时势造英雄,正是因为 HTTP 存在着诸多不足,所以,才诞生了 SPDY。2009年,谷歌公开了自行研发的 SPDY 协议,主要解决 HTTP/1.1 效率不高的问题。它的设计目标是降低 50% 的页面加载时间。

  • 多路复用(multiplexing)。多个请求共享一个 tcp 连接。
  • header 压缩。删除或者压缩 HTTP 头
  • 服务端推送。提供服务方发起通信,并向客户端推送数据的机制。

SPDY 位于 HTTP 之下,TCP 和 SSL 之上,这样可以轻松兼容老版本的 HTTP 协议

🥳 HTTP 版本 - 图3

实际上在 HTTP2 提出来之前,SPDY 流行了很长一段时间。当下很多著名的互联网公司都在自己的网站或 APP 中采用了 SPDY 系列协议(当前最新版本是 SPDY/3.1),因为它对性能的提升是显而易见的。主流的浏览器(谷歌、火狐、Opera)也都早已经支持 SPDY,它已经成为了工业标准。HTTP Working-Group 最终决定 以 SPDY/2 为基础,开发 HTTP/2

HTTP/2.0

HTTP/2 是 HTTP 协议自 1997 年 HTTP 1.1 发布后的首个更新,主要基于 SPDY 协议。由互联网工程任务组(IETF)的 Hypertext Transfer Protocol Bis(httpbis)工作小组进行开发。该组织于 2014年12月 将 HTTP/2 标准提议递交至 IESG 进行讨论,于 2015 年 2 月 17 日被批准。HTTP/2 标准于 2015 年 5 月以 RFC 7540 正式发表。

二进制分帧

在 HTTP/2 中,在应用层(HTTP2.0)和传输层(TC P或 UDP)之间加了一层:二进制分帧层。

这是 HTTP2 中最大的改变。HTTP2 之所以性能会比 HTTP1.1 有那么大的提高,很大程度上依靠这一层的引入。

🥳 HTTP 版本 - 图4

多路复用

多路复用允许同时通过单一的 HTTP/2.0 连接发起多重的请求-响应消息。在 HTTP1.1 协议中,浏览器客户端在同一时间,针对同一域名下的请求有一定数量的限制,超过了这个限制的请求就会被阻塞。而多路复用允许同时通过单一的 HTTP2.0 连接发起多重的消「请求-响应」消息。
🥳 HTTP 版本 - 图5
HTTP2 的请求的 TCP 的 connection 一旦建立,后续请求以 stream 的方式发送。每个 stream 的基本组成单位是frame(二进制帧)。客户端和服务器可以把 HTTP 消息分解为互不依赖的帧,然后乱序发送,最后再在另一端把它们重新组合起来。

🥳 HTTP 版本 - 图6

Header 压缩

HTTP/1.1 的 header 带有大量信息,而且每次都要重复发送。HTTP/2 为了减少这部分开销,采用了 HPACK 头部压缩算法对 Header 进行压缩。

🥳 HTTP 版本 - 图7

Hapck原理

具体规则可以描述为:

  • 通信双方共同维护了一份 静态表,包含了常见的头部名称与值的组合
  • 根据先入先出的原则,维护一份可动态添加内容的 动态表
  • 用基于该静态哈夫曼码表的哈夫曼编码数据
    当要发送一个请求时,会先将其头部和静态表对照,对于完全匹配的键值对,可以直接使用一个数字表示,如method: GET,对于头部名称匹配的键值对,可以将名称使用一个数字传输,同时告诉服务端将它添加到动态表中,以后的相同键值对就用一个数字表示了。这样,像cookie这些不经常变动的值,只用发送一次就好了。

服务端推送

🥳 HTTP 版本 - 图8

HTTP/2 存在的问题

从HTTP/1.0诞生,一直到HTTP/2,在这24年里,HTTP协议已经做过了三次升级,但是有一个关键的技术点是不变的,那就是这所有的HTTP协议,都是基于TCP协议实现的。
**

基于 TCP 带来的限制

TCP协议虽然更加可靠,但是还是存在着一定的问题,这部分内容可参考 TCP 篇。
**

升级 TCP 不可行


TCP 存在诸多问题,并且升级 TCP 是不可行的,
涉及协议僵化**,原因如下:

  • 网络传输需要众多中间设备,无法强制中间设备升级
  • TCP协议需要通过操作系统内核实现,而操作系统的更新也是滞后的

放弃 TCP

既然升级 TCP 不可行,那么只能放弃 TCP。放弃 TCP 后存在两个选择:

  • 创建全新的协议
  • 在已有协议上进行改造

创建全新协议也会受 中间设备僵化 的影响,因此只能选择在已有协议上进行改造,UDP 便是一个绝佳的选择

HTTP/3.0

QUIC 协议

Google 在 2013 年推出了 QUIC 协议(Quick UDP Internet Connections),从名字便可以看出,它是一种完全基于 UDP 的协议。

在设计之初,Google 就希望使用这个协议来取代 HTTPS/HTTP 协议,使网页传输速度加快。2015年6月,QUIC的网络草案被正式提交至互联网工程任务组。2018 年 10 月,互联网工程任务组 HTTP 及 QUIC 工作小组正式将基于 QUIC 协议的 HTTP(英语:HTTP over QUIC)重命名为 HTTP/3

QUIC协议有以下特点:

  • 基于 UDP 的传输层协议:它使用 UDP 端口号来识别指定机器上的特定服务器
  • 可靠性:虽然 UDP 是不可靠传输协议,但是 QUIC 在 UDP 的基础上做了些改造,使得它 提供了和 TCP 类似的可靠性。它提供了 数据包重传、拥塞控制、调整传输节奏以及其他一些 TCP 中存在的特性
  • 实现了无序、并发字节流:QUIC 的单个数据流可以保证有序交付,但多个数据流之间可能乱序,这意味着单个数据流的传输是按序的,但是多个数据流中接收方收到的顺序可能与发送方的发送顺序不同
  • 快速握手:QUIC 提供 0-RTT 和 1-RTT 的连接建立
  • 使用 TLS 1.3 传输层安全协议:与更早的 TLS 版本相比,TLS 1.3 有着很多优点,但使用它的最主要原因是其握手所花费的往返次数更低,从而能降低协议的延迟。

🥳 HTTP 版本 - 图9

自定义连接机制

对于 TCP 连接的识别,需要通过服务器和客户端过双方的 ip端口 四个参数进行的。在网络切换的场景中,比如手机切换网络,那么自身的 ip 就会发生变化。这就导致之前的 TCP 连接就会失效,就需要重新建立。

QUIC 协议使用特有的 UUID 来标记每一次连接,在网络环境发生变化的时候,只要 UUID 不变,就能不需要握手,继续传输数据。

自定义重传机制

TCP 为了保证可靠性,通过使用 序号 应答 机制,来解决顺序问题和丢包问题。但在 TCP 里面超时的采样存在不准确的问题。例如,发送一个包,序号为 100,发现没有返回,于是再发送一个 100,过一阵返回一个 ACK101。这个时候客户端知道这个包肯定收到了,但是往返时间是多少呢?是 ACK 到达的时间减去后一个 100 发送的时间,还是减去前一个 100 发送的时间呢?事实是,第一种算法把时间算短了,第二种算法把时间算长了。

QUIC 也有个序列号,是递增的,并且引入了 offset 的概念。QUIC 既然是面向连接的,也就像 TCP 一样,是一个数据流,发送的数据在这个数据流里面有个偏移量 offset,可以通过 offset 查看数据发送到了哪里,这样只要这个 offset 的包没有来,就要重发;如果来了,按照 offset 拼接,还是能够拼成一个流。

🥳 HTTP 版本 - 图10

无阻塞的多路复用

当其中一个数据包遇到问题,TCP 连接需要等待这个包完成重传之后才能继续进行。虽然 HTTP 2.0 通过多个 stream,使得逻辑上一个 TCP 连接上的并行内容,进行多路数据的传输,然而这中间并没有关联的数据。一前一后,前面 stream 2 的帧没有收到,后面 stream 1 的帧也会因此阻塞

有了自定义的连接和重传机制,我们就可以 解决上面 HTTP 2.0 的多路复用问题。同 HTTP 2.0 一样,同一条 QUIC 连接上可以创建多个 stream,来发送多个 HTTP 请求。但是,QUIC 是基于 UDP 的,一个连接上的多个 stream 之间没有依赖。这样,假如 stream2 丢了一个 UDP 包,后面跟着 stream3 的一个 UDP 包,虽然 stream2 的那个包需要重传,但是 stream3 的包无需等待,就可以发给用户

自定义流量控制

TCP 的流量控制是通过滑动窗口协议。QUIC 的流量控制也是通过 window_update,来告诉对端它可以接受的字节数。但是 QUIC 的窗口是适应自己的多路复用机制的,不但在一个连接上控制窗口,还在一个连接中的每个 stream 控制窗口。