# HTTP1/2/3

<figure><img src="https://4183825214-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FbsZ9Ehk2rNaKFlSBokuF%2Fuploads%2FufFwenyteVIzY5JdfKWo%2Fimage.png?alt=media&#x26;token=add7eb0f-7ff3-4559-b764-f37b49671c78" alt=""><figcaption></figcaption></figure>

#### http1.1

* &#x20;HTTP/1.1 的实现是基于请求-响应模型的。同一个连接中，HTTP 完成一个事务（请求与响应），才能处理下一个事务，也就是说在发出请求等待响应的过程中，是没办法做其他事情的，如果响应迟迟不来，那么后续的请求是无法发送的，也造成了**队头阻塞**的问题。
* HTTP1.1是一种基于文本的协议，而HTTP2和HTTP3是基于二进制的协议。
* HTTP1.1使用明文文本进行通信，而HTTP2和HTTP3使用二进制帧进行通信，这使得HTTP2和HTTP3可以更高效地传输数据。
* HTTP/1.1 不支持服务器主动推送资源给客户端，都是由客户端向服务器发起请求后，才能获取到服务器响应的资源。HTTP2和HTTP3都支持服务器推送，可以在客户端请求之前向客户端发送资源，从而提高性能。

***

HTTP/1.1 报文中 Header 部分存在的问题：

* 含很多固定的字段，比如 Cookie、User Agent、Accept 等，这些字段加起来也高达几百字节甚至上千字节，所以有必要**压缩**；
* 大量的请求和响应的报文里有很多字段值都是重复的，这样会使得大量带宽被这些冗余的数据占用了，所以有必须要**避免重复性**；
* 字段是 ASCII 编码的，虽然易于人类观察，但效率低，所以有必要改成**二进制编码**；

HTTP/2 对 Header 部分做了大改造，把以上的问题都解决了。

HTTP/2 没使用常见的 gzip 压缩方式来压缩头部，而是开发了 **HPACK** 算法，HPACK 算法主要包含三个组成部分：

* 静态字典；
* 动态字典；
* Huffman 编码（压缩算法）；

对于常见的 HTTP 头部通过**静态表和 Huffman 编码**的方式，将体积压缩了近一半，而且针对后续的请求头部，还可以建立**动态表**，将体积压缩近 90%，大大提高了编码效率，同时节约了带宽资源。

***

#### http2

* HTTP2引入了多路复用技术，允许在单个TCP连接上同时发送多个请求和响应，从而提高了性能。HTTP1.1只能在一个TCP连接上发送一个请求和响应。
* 多个 Stream 跑在一条 TCP 连接，同一个 HTTP 请求与响应是跑在同一个 Stream 中，HTTP 消息可以由多个 Frame 构成， 一个 Frame 可以由多个 TCP 报文构成。
* 在 HTTP/2 连接上，**不同 Stream 的帧是可以乱序发送的（因此可以并发不同的 Stream ）**，因为每个帧的头部会携带 Stream ID 信息，所以接收端可以通过 Stream ID 有序组装成 HTTP 消息，而**同一 Stream 内部的帧必须是严格有序的**。
* **服务器支持主动推送资源**，大大提升了消息的传输性能，服务器推送资源时，会先发送 PUSH\_PROMISE 帧，告诉客户端接下来在哪个 Stream 发送资源，然后用偶数号 Stream 发送资源给客户端。

***

HTTP/2 通过头部压缩、二进制编码、多路复用、服务器推送等新特性大幅度提升了 HTTP/1.1 的性能，而美中不足的是 HTTP/2 协议是基于 TCP 实现的，于是存在的缺陷有三个。

* 队头阻塞；
* TCP 与 TLS 的握手时延迟；
* 网络迁移需要重新连接；

**队头阻塞**：HTTP/2 多个请求是跑在一个 TCP 连接中的，那么当 TCP 丢包时，整个 TCP 都要等待重传，那么就会阻塞该 TCP 连接中的所有请求。因为 TCP 是字节流协议，TCP 层必须保证收到的字节数据是完整且有序的，如果序列号较低的 TCP 段在网络传输中丢失了，即使序列号较高的 TCP 段已经被接收了，应用层也无法从内核中读取到这部分数据，从 HTTP 视角看，就是请求被阻塞了。

**握手延迟**：发起 HTTP 请求时，需要经过 TCP 三次握手和 TLS 四次握手（TLS 1.2）的过程，因此共需要 3 个 RTT 的时延才能发出请求数据。

**重新连接**：一个 TCP 连接是由四元组（源 IP 地址，源端口，目标 IP 地址，目标端口）确定的，这意味着如果 IP 地址或者端口变动了，就会导致需要 TCP 与 TLS 重新握手，这不利于移动设备切换网络的场景，比如 4G 网络环境切换成 WiFi。

UDP 是一个简单、不可靠的传输协议，而且是 UDP 包之间是无序的，也没有依赖关系。UDP 是不需要连接的，也就不需要握手和挥手的过程，所以天然的就比 TCP 快。

HTTP/3 不仅仅只是简单将传输协议替换成了 UDP，还基于 UDP 协议在「应用层」实现了 **QUIC 协议**，它具有类似 TCP 的连接管理、拥塞窗口、流量控制的网络特性，相当于将不可靠传输的 UDP 协议变成“可靠”的了，所以不用担心数据包丢失的问题。

***

#### http3

* HTTP/2只在应用层（HTTP层）解决了队头阻塞，但TCP层的阻塞仍然存在。HTTP/3通过QUIC解决了底层的队头阻塞问题，因为它在传输层就支持了多路复用和独立流的概念。
* HTTP3使用QUIC协议，而HTTP1.1和HTTP2使用TCP协议。QUIC是基于UDP协议的，具有更好的性能和安全性。HTTP3还引入了0-RTT（零往返时间）握手，可以更快地建立连接。
* QUIC 提供可靠、有序的加密握手数据传输。 QUIC 数据包保护用于尽可能多地加密握手协议。加密握手必须提供以下属性：
  * 经过身份验证的密钥交换，其中
    * 服务器始终经过身份验证，
    * 客户端可以选择进行身份验证，
    * 每个连接都会产生不同且不相关的密钥，并且
    * 密钥材料可用于 0-RTT 和 1-RTT 数据包的数据包保护。

{% embed url="<https://juejin.cn/post/7079936383925616653>" %}
