HTTP

HTTP 协议发展史

48twx

HTTP1.x

HTTP 请求报文结构

http1 中奠定了 http 协议的基本语义:由请求行/状态行、body 和 header 构成

HTTP 请求协议

ecg6l

HTTP 响应协议

8v8iv

HTTP1.1 管道化(没有解决 HTTP1.x 的队头阻塞)

什么是 HTTP1.1 管道化
HTTP1.1 允许在持久连接上可选的使用请求管道,这是相对于 keep-alive 连接的又一次性能优化。在相应请求到达之前,可以将多条请求放入队列,当第一条请求发往服务器的时候,第二第三条请求也可以开始发送了,在高延时的网络条件下,这样可以降低网络的 RTT,提高性能。

a6tks

HTTP 管道化的限制

  1. 管道化要求服务器按照请求发送的顺序返回响应(FIFO),原因很简单,HTTP 请求和响应并没有序号标识,无法将乱序的响应和请求关联起来
  2. 客户端需要保持未收到响应的请求的连接,当连接意外中断时,需要重新发送这部分请求
  3. 只有幂等的请求才能进行管道化,即 GET 和 HEAD 请求才能管道化,否则可能会出现意料之外的结果
  4. HTTP 管道化没有解决 HTTP 队头阻塞:HTTP 管道化要求服务端必须按照请求发送的顺序返回响应,那如果一个响应返回延迟了,那么其后续的响应都会被延迟,直到队头的响应送达。

HTTP1.1 协议缺点

HTTP1.1 有两个主要的缺点:安全不足和性能不高

队头阻塞 (Head-Of-Line Blocking) — 高延迟,性能差

网络延迟问题主要由于队头阻塞导致带宽无法被充分利用。
队头阻塞:当顺序发送的请求序列中的一个请求因为原因被阻塞时,在后面排队的所有请求也一并被阻塞,会导致客户端迟迟收不到数据。
HTTP1.1 缓解队头阻塞问题通过:并发连接和域名分片,本质还是提高一个域名下的 TCP 连接数,并没有本质上解决 HTTP 队头阻塞问题
具体解决方案见 HTTP相关面试题→TCP队头阻塞和HTTP队头阻塞怎么解决?

明文传输 — 不安全性

HTTP1.1 传输数据时,所有传输的内容都是明文,客户端和服务器都无法验证对方的身份,无法保证数据的安全性

无状态特性 — 阻碍交互

HTTP特点→无状态性

不支持服务端推送消息

HTTP2.x

SPDY

由于 HTTP1.x 的缺陷,引入了雪碧图、将小图内联、使用多个域名等等的方式来提高性能,不过这些优化都绕开了 HTTP 协议。直到 2009,Google 公开了自研的 SPDY 协议,主要解决了 HTTP1.1 效率不高的问题,SPDY 的推出算正式改造 HTTP 协议本身。降低延迟、压缩 Header 等,最终也带来了 HTTP2 的诞生。

yuq36

HTTP2 简介

2015 年,HTTP2 发布,兼容 HTTP1.1,HTTP2 基于 SPDY,专注于性能,最大的一个目标是在用户和网站间只用一个连接。使用 HTTP2 能带来 20%~60% 的效率提升。

HTTP2 新特性

为了解决 HTTP1.x 的问题,HTTP2 诞生了,HTTP2 性能提升主要有两点:

还有一些颠覆性的功能实现:

HTTP/2 传输数据量的大幅减少,主要有两个原因:以二进制方式传输和 Header 压缩

二进制传输 (二进制分帧)

HTTP2 把报文从文本全部换成二进制格式了,二进制协议解析起来更高效,HTTP2 将请求和响应数据分割为更小的帧,并且它们采用二进制编码。
把 TCP 协议的部分特性摞到了应用层,把原来的 Headers+Body 的报文消息打散为数个小片的二进制帧 (Frame)。用HEADERS 帧存放头部字段,DATA 帧存放请求体数据。分帧之后,服务器看到的不再是一个个完整的 HTTP 请求报文,而是一堆乱序的二进制帧。这些二进制帧不存在先后关系,因此也就不会排队等待,也就没有了 HTTP 的队头阻塞问题。
通信双方都可以给对方发送二进制帧,这种二进制帧的双向传输的序列,也叫做流,HTTP2 用流来在一个 TCP 连接上来进行多个数据帧的通信,这就是多路复用的概念。
如何保证乱序的数据帧?
乱序指的是不同 ID 的 Stream 是乱序的,同一个 StreamID 的帧一定是按顺序传输的,二进制帧到达后对方会将 StreamID 相同的二进制帧组装成完成的请求报文和响应报文。

头部编码 (Header 压缩)-HPack 算法

HTTP1.x 时代,请求体一般有响应的压缩编码过程,通过 Content-Encoding 头部字段来指定。HTTP2 针对头部字段,并没有使用传统的压缩算法,而是开发了专门的压缩算法——HPACK 算法,对请求头进行压缩
HPack 算法:服务器和客户端之间建立哈希表 (字典),将用到的字段存放在这张表中,那么在传输的时候对于之前出现过的值,只需要把索引传给对方即可,对方拿到索引查表即可,这种传索引的方式,让请求头字段得到极大程度的精简和复用;还采用哈夫曼编码来压缩整数和字符串,可以达到 50%~90% 的高压缩率。
具体来说:

8028t

多路复用

HTTP2 有了二进制分帧之后,HTTP2 不再依赖 TCP 连接去实现多流并行了:

同个域名只需要占用一个 TCP 连接,使用一个 TCP 连接并行发送多个请求和响应,这样整个页面资源的下载过程只需要一次慢启动,同时也避免了多个 TCP 连接竞争带宽所带来的问题

并行交错地发送多个请求/响应,请求/响应之间互不影响,不像 HTTP1.x 那样排队阻塞

多路复用的技术可以只通过一个 TCP 连接就可以传输所有的请求数据:
wrp86

服务器推送 (Server Push)

HTTP2 还在一定程度上改变了传统的 " 请求 - 应答 " 工作模式,服务器不再是完全被动地响应请求,也可以新建 " 流 " 主动向客户端发送消息。比如,在浏览器刚请求 HTML 的时候就提前把可能会用到的 JS、CSS 文件发给客户端,减少等待的延迟,这被称为 " 服务器推送 "( Server Push,也叫 Cache push)

另外需要补充的是,服务端可以主动推送,客户端也有权利选择是否接收。如果服务端推送的资源已经被浏览器缓存过,浏览器可以通过发送 RST_STREAM 帧来拒收。主动推送也遵守同源策略,换句话说,服务器不能随便将第三方资源推送给客户端,而必须是经过双方确认才行。

HTTP2 缺点

虽然 HTTP2 解决了很多之前旧版本的问题,但是它还是存在一个巨大的问题,主要是底层支撑的 TCP 协议造成的。HTTP2 的主要缺点:

  1. TCP 以及 TCP+TLS 建立连接慢,延时
  2. TCP 的队头阻塞并没有彻底解决
  3. 多路复用导致服务器压力上升
  4. 多路复用容易 timeout

建立连接慢,延时(还是和 HTTP1.x 一样,未优化)

HTTP2 还是使用 TCP 协议来传输的,如果使用 HTTPS 的话,还需要使用 TLS 协议进行安全传输,而 TLS 还有一个握手过程,这样就需要两个握手延迟过程

总之,在传输数据之前,需要花费 2~4 个 RTT。

RTT(Round-Trip Time):往返时延,表示从发送端发送数据开始,到发送端收到来自接收端的确认(接收端收到数据后立即发送确认),总共经历的时延。

TCP 队头阻塞未解决

HTTP2 只解决了 HTTP 的队头阻塞,未解决底层 TCP 队头阻塞问题。
HTTP2 多个请求是跑在一个 TCP 连接中,当出现了丢包时,HTTP2 的表现反倒不如 HTTP1.x 了。因为 TCP 为了保证可靠传输,有个 丢包重传 机制,丢失的包必须要等待重新传输确认,HTTP2 出现丢包时,整个 TCP 都要开始等待重传,那么就会阻塞该 TCP 连接上的所有请求,而对于 HTTP1.1 来说,可以开启多个 TCP 连接,出现这种情况反倒只会影响其中一个连接,剩余的 TCP 连接还可以正常传输数据。
8wh4l

因为 http2 使用的是多路复用的流模型,一个 tcp 连接的发送数据过程中可能会把一个个请求分割成多个流发送到服务器,因为 tcp 的 tls 加密是一个 record 的加密,也就是接近 10stream 大小进行加密,如果其中在某一个流丢失了,整一串都会解密失败。这就是 http2 最为严重的队头阻塞问题。

多路复用压力大,容易 timeout

多路复用没有限制同时请求数,请求的平均数量与往常相同,但实际会有许多请求的短暂爆发,导致瞬时 QPS 暴增。
大批量的请求同时发送,由于 HTTP2 连接上存在多个并行的流,而网络带宽和服务器资源优先,每个流的资源都会被稀释,虽然它们开始时间相差更短,但却都可能超时。

网络切换导致四元组变化,需要重建连接

  1. 基于 TCP 四元组确定一个链接,在移动互联网中表现不佳。因为移动设备经常移动,可能在公交地铁等地方,出现了基站变换,Wi-Fi 变化等状态。导致四元组发声变化,而需要重新建立连接

QUIC/HTTP3.x

QUIC 章节

HTTP 协议

HTTP 协议组成

HTTP1.x 报文结构

请求报文
z8j1u

响应报文
0k6w9

HTTP 请求方法

http/1.1 规定了以下请求方法 (注意,都是大写):

  1. GET 通常用来获取资源,没有 body,幂等性
  2. POST 增加或修改资源 (上传数据),有 body
  3. PUT 修改资源,有 body,幂等性
  4. DELETE 删除资源,幂等性
  5. HEAD 获取资源的元信息
  6. CONNECT 建立连接隧道,用于代理服务器
  7. OPTIONS 列出可对资源实行的请求方法,用来跨域请求
  8. TRACE 追踪请求 - 响应的传输路径

HTTP 状态码

RFC 规定 HTTP 的状态码为三位数,被分为五类:

1xx

2xx

3xx

  1. 比如你的网站从 HTTP 升级到了 HTTPS 了,以前的站点再也不用了,应当返回 301,这个时候浏览器默认会做缓存优化,在第二次访问的时候自动访问重定向的那个地址。
  2. 如果只是暂时不可用,那么直接返回 302 即可,和 301 不同的是,浏览器并不会做缓存优化。

4xx

5xx

HTTP 请求头有哪些?

数据类型、压缩格式、语言和字符集(Content-Type、Content-Encoding、Content-Languages)

6e1op

Content-Type/Accept 发送端发送的数据 MIME 类型

发送端发送的数据格式 Content-Type,接收端对应 Accept

Content-Encoding/Accept-Encoding 发送端压缩格式

Accept-Encoding 和 Content-Encoding 是 HTTP 中用来对采用哪种编码格式传输正文进行协定的一对头部字段;发送端数据的压缩格式 Content-Encoding,接收端 Accept-Encoding

Content-Language/Accept-Language 支持的语言

发送端的语言 Content-Language,接收端 Accept-Language

字符集

发送端的字符集 Content-Type: text/html; charset=utf-8,接收端 Accept-Charset: charset=utf-8

定长和分块传输(Content-Length 和 chunked)

Content-Length 定长

响应头 Content-Length 指明内容的固定大小

Transfer-Encoding 不定长

响应头 Transfer-Encoding: chunked,表示分块传输数据,设置这个 header 后有两个效果:

大文件传输、分块传输(Range 和 Content-Range)

客户端请求用 Range,服务端返回用 Content-Range

Range

对于客户端而言,它需要指定请求哪一部分,通过 Range 这个请求头字段确定,格式为 Range: bytes=x-y,x1-y1

// 请求单段数据
Range: bytes=0-9
// 请求多段数据
Range: bytes=0-9, 30-39

1. HTTP请求头字段
Range头指示服务器只传输一部分Web资源。这个头可以用来实现断点续传功能。Range字段可以通过三种格式设置要传输的字节范围:
Range:bytes=1000-2000    传输范围从1000到2000字节。
Range:bytes=1000-   传输Web资源中第1000个字节以后的所有内容。
Range bytes=1000   传输最后1000个字节。

2. HTTP响应消息头字段
Accept-Ranges:这个字段说明Web服务器是否支持Range支持,则返回Accept-Ranges:bytes,如果不支持,则返回Accept-Ranges:none.
Content-Range:指定了返回的Web资源的字节范围。这个字段值的格式是:例子: Content-Range:1000-3000/5000

可用于实现断点下载续传功能

Content-Range
HTTP/1.1 206 Partial Content
Content-Length: 10
Accept-Ranges: bytes
Content-Range: bytes 0-9/100 // 0-9表示请求的返回,100表示资源的总大小

i am xxxxx
HTTP/1.1 206 Partial Content
Content-Type: multipart/byteranges; boundary=00000010101 // 多段数据、响应体中的分隔符
Content-Length: 189
Connection: keep-alive
Accept-Ranges: bytes


--00000010101
Content-Type: text/plain
Content-Range: bytes 0-9/96

i am xxxxx
--00000010101
Content-Type: text/plain
Content-Range: bytes 20-29/96

eex jspy e
--00000010101-- // 分隔末尾添上--表示结束
http 分块传输原理

http 协议定义的分块传输的响应 header 字段,具体是否支持取决于 server 的实现,通过在请求头加上 range 字段来验证服务器是否支持分块传输:

curl -H "Range: bytes=0-10" http://download.dcloud.net.cn/HBuilder.9.0.2.macosx_64.dmg -v
# 请求头
> GET /HBuilder.9.0.2.macosx_64.dmg HTTP/1.1
> Host: download.dcloud.net.cn
> User-Agent: curl/7.54.0
> Accept: */*
> Range: bytes=0-10
# 响应头
< HTTP/1.1 206 Partial Content
< Content-Type: application/octet-stream
< Content-Length: 11
< Connection: keep-alive
< Date: Thu, 21 Feb 2019 06:25:15 GMT
< Content-Range: bytes 0-10/233295878

在请求头中添加 "Range: bytes=0-10" 的作用是,告诉服务器本次请求我们只想获取文件 0-10(包括 10,共 11 字节) 这块内容。如果服务器支持分块传输,则响应状态码为 206,表示 " 部分内容 ",并且同时响应头中包含 "Content-Range" 字段,如果不支持则不会包含

Content-Range: bytes 0-10/233295878
0-10 表示本次返回的区块,233295878 代表文件的总长度,单位都是 byte, 也就是该文件大概 233M 多一点。
简单的设计一个多线程的文件分块下载器:

  1. 先检测是否支持分块传输,如果不支持,直接下载;如果支持,将剩余内容分块下载
  2. 各个分块下载时保存到各自临时文件,等待所有分块下载完成后合并临时文件
  3. 删除临时文件

HTTP 表单数据

在 HTTP 中,有两种主要的表单提交的方式,体现在两种不同的 Content-Type 取值:

application/x-www-form-urlencoded URL 编码

如 a=1&b=2,转换为 a%3D1%26b%3D2

multipart/form-data
Content-Disposition: form-data;name="data1";
Content-Type: text/plain
data1
----WebkitFormBoundaryRRJKeWfHPGrS4LKe
Content-Disposition: form-data;name="data2";
Content-Type: text/plain
data2
----WebkitFormBoundaryRRJKeWfHPGrS4LKe--

HTTP 缓存

HTTP 缓存相关 Header

Expires

在 HTTP1.0,响应使用 Expires 头标识缓存的有效期,其值是一个绝对时间,当客户端再次发出网络请求时可比较当前时间和上次响应的 Expires 时间进行比较,来决定是使用缓存还是发起新的请求

⽐如 Expires:Thu,31 Dec 2020 23:59:59 GMT。使用 Expires 最大的问题是它依赖客户端的本地时间,如果用户自己修改了本地时间,就会导致无法准确的判断缓存是否过期。

Cache-Control

HTTP1.1 推出,优先级高于 Expires。主要值有:

  1. private 默认值,标识那些私有的业务逻辑数据,比如根据用户行为下发的推荐数据。该模式下网络链路中的代理服务器等节点不应该缓存这部分数据,因为没有实际意义。
  2. public 内容是公开的,中间节点可缓存。public 和 private 相反,用于标识那些通用的业务数据,比如获取新闻列表,所有人看到的都是同一份数据,因此客户端、代理服务器都可以缓存
  3. no-cache 可进行缓存,但在客户端使用缓存前必须去服务器进行缓存资源有效性的验证
  4. max-age 表示缓存时长,单位为秒,指一个时间段,比如一年,通常用于不经常变化的静态资源
  5. no-store 任何节点禁止使用缓存

HTTP 缓存原理

强制缓存

网络请求响应 header 标识了 Expires 或 Cache-Control 带了 max-age 信息,客户端计算缓存并未过期,则可以直接使用本地缓存内容,而不用真正的发起一次网络请求

强制缓存缺点:一旦服务器有资源更新,直到缓存时间截止前,客户端无法获取到最新的资源(除非请求时手动添加 no-store 头)

协商缓存

几种头来实现协商缓存:

  1. Last-Modified/If-Modified-Since 头

这套方案问题:

  1. If-None-Match/Etag 头

标签,类似指纹。流程和 Last-Modified 一样,只是把服务器响应头换成 ETag,客户端发出请求的头变成了 If-None-Match。
ETag 是资源的唯一标识,服务端资源变化一定会导致 ETag 变化。ETag 具体的生成方式由服务端控制,常见的影响因素包括:文件最终修改时间、文件大小、文件编号等。

URI 和 URL?

URI, 全称为 (Uniform Resource Identifier), 也就是统一资源标识符,它的作用很简单,就是区分互联网上不同的资源。但是,它并不是我们常说的网址, 网址指的是 URL, 实际上 URI 包含了 URN 和 URL 两个部分,由于 URL 过于普及,就默认将 URI 视为 URL 了。
URI 只能使用 ASCII, ASCII 之外的字符是不支持显示的,需要编码。

URI 结构
vra0p

https://www.baidu.com/s?wd=HTTP&rsv_spt=1

HTTP 特点

灵活可扩展

HTTP 协议只规定了基本格式;另一个是传输形式的多样性,不仅仅可以传输文本,还能传输图片、视频等任意数据,非常方便。

可靠传输

HTTP 基于 TCP/IP,因此把这一特性继承了下来

请求 - 应答

也就是一发一收、有来有回

无状态性

无状态性指的是 HTTP 协议对于事物处理没有记忆能力,每一次请求之间是没有联系的,都是独立的,服务器不知道请求两次之间是否是同一个用户。

TCP 有状态吗?

TCP 是有状态的,在一次 TCP 连接中,每一次的数据交换都和上一次紧密相关的,TCP 报文存在 ACK 字段用于确认上次接收的报文,每一次 TCP 数据交换双方都是能够确切知道对方的信息。

为什么基于 TCP 的 HTTP 是无状态的?

HTTP 协议利用 TCP 协议来进行数据传输的,因为它们本身并没有强关联,它们处于 OSI 不同层次(HTTP 应用层协议,TCP 属于传输层协议),不能说 TCP 是有状态,HTTP 协议就有状态

HTTP1.1 后支持了 keep-alive,那么每次 HTTP 请求还是无状态吗?

也是无状态,不同的请求还是按队列来响应的,它们之间没有任何关联

为什么不改进 http 协议使之有状态?

最初的 http 协议只是用来浏览静态文件的,无状态协议已经足够,这样实现的负担也很轻(相对来说,实现有状态的代价是很高的,要维护状态,根据状态来操作。)引入了 Cookie 和 Session 来保证有状态。

HTTP 缺点

  1. 无状态

在需要长连接的场景中,需要保存大量的上下文信息,以免传输大量重复的信息,那么这时候无状态就是 http 的缺点了。
但与此同时,另外一些应用仅仅只是为了获取一些数据,不需要保存连接上下文信息,无状态反而减少了网络开销,成为了 http 的优点。

  1. 明文传输 数据不安全
  2. 队头阻塞问题

当 HTTP 开启长连接时,共用一个 TCP 连接,同一时刻只能处理一个请求,那么当前请求耗时过长的情况下,其它的请求只能处于阻塞状态,也就是著名的HTTP 队头阻塞问题。

HTTP 和 HTTPS 的区别?

HTTPS 相比 HTTP 最大的不同就是多了一层 SSL (Secure Sockets Layer 安全套接层) 或 TLS (Transport Layer Security 安全传输层协议)。

背景

HTTP 协议是无状态的,无状态意味着,服务器无法给不同的客户端响应不同的信息。这样一些交互业务就无法支撑了。Cookie 应运而生。

什么是 Cookie?
Cookie 是浏览器里存储的一个很小的文本文件,内部以键值对的方式来存储;Cookie 是客户端保存用户信息的一种机制,用来记录用户的一些信息。

Cookie 最大的作用就是存储 sessionID 用来唯一标识用户。
Cookie 不可跨域名

Cookie 流程

  1. Client 发送 HTTP 请求给 Server
  2. Server 响应,并附带 set-cookie 的头信息
  3. Client 保存 Cookie,之后请求 Server 会覆盖 cookie:xxx 的头信息
  4. Server 从 Cookie 知道 Client 是谁了,返回相应的响应

Cookie 缺点

  1. 安全缺陷 Cookie 很容易被非法用户截获,然后进行一系列的篡改,最后在 Cookie 的有效期内重新发送给服务器
  2. 容量缺陷:体积上限只有 4K,只能用来存储少量的信息
  3. 性能缺陷:Cookie 紧跟域名,因此域名下的请求都会携带上完整的 Cookie,造成性能浪费,因为请求携带了很多不必要的内容。

Session

什么是 Session?

Session 缺点

  1. Session 信息保存在服务器,会话多了后,服务器压力增大
  2. SessionID 存储在 Cookie,还是有暴露的风险,比如 CSRF(Cross-Site Request Forgery,跨站请求伪造)

Token 令牌

Token 就是一段字符串,Token 传递的过程跟 Cookie 类似,只是传递对象变成了 Token。用户使用用户名、密码请求服务器后,服务器就生成 Token,在响应中返给客户端,客户端再次请求时附带上 Token,服务器就用这个 Token 进行认证鉴权。
Token 一般放 header,不放 body 或 url query,否则和请求业务的参数混合在一起,导致代码混乱

Http 错误

线上问题 -ERR_CONNECTION_CLOSED

问题:线上一个链接在不登录时能正常打开,登录后就打不开报错 ERR_CONNECTION_CLOSED
分析:登录后有很多 ABT 参数会被设置到 request header,导致 header 过大,报错
解决:header 数据不要过大

HTTP 相关面试题

HTTP 队头阻塞和 TCP 队头阻塞?怎么解决?

HTTP1.x 队头阻塞问题

HTTP 传输是基于请求 - 响应的模型进行的,报文必须是一发一收,里面的任务被放在一个任务队列中串行执行,一旦队首的请求处理太慢,就会阻塞后面请求的处理,这就是HTTP 队头阻塞问题。
HTTP1.1 如何解决队头阻塞问题?(未基于 HTTP 本身解决队头阻塞问题)

HTTP 管道化没有解决 HTTP 队头阻塞问题, 原因是 HTTP 管道化,客户端可以并行的发送请求,但服务器必须串行的处理客户端的请求,一个个响应,如果前一个请求慢,那就会阻塞后面请求的响应

HTTP/1.1 管道 (pipelining) 解决了队头阻塞问题?

没有。
6wezq

HTTTP2 如何解决 HTTP 队头阻塞

HTTP1.1 并没有真正从 HTTP 本身层面解决该问题,只是增加了 TCP 连接,分摊风险而已。多条 TCP 连接会竞争有限的带宽,让真正优先级高的请求不能优先处理。而 HTTP2 从 HTTP 协议本身解决了队头阻塞问题。
HTTP2 引入了帧、消息和数据流等概念,每个请求/响应被称为消息,每个消息都被拆分成若干个帧进行传输,每个帧都分配一个序号。每个帧在传输是属于一个数据流,而一个连接上可以存在多个流,各个帧在流和连接上独立传输,到达之后在组装成消息,这样就避免了请求/响应阻塞。
把 TCP 协议的部分特性摞到了应用层,把原来的 Headers+Body 的报文消息打散为数个小片的二进制帧 (Frame)。用HEADERS 帧存放头部字段,DATA 帧存放请求体数据。分帧之后,服务器看到的不再是一个个完整的 HTTP 请求报文,而是一堆乱序的二进制帧。这些二进制帧不存在先后关系,因此也就不会排队等待,也就没有了 HTTP 的队头阻塞问题。

HTTP 队头阻塞和 TCP 队头阻塞

HTTP2 的 TCP 队头阻塞 (TCP 丢包重传)

HTTTP2 还是基于 TCP 协议的,还是存在 TCP 队头阻塞问题。TCP 中的队头阻塞的产生是由 TCP 自身的实现机制决定的,无法避免。想要在应用程序当中避免 TCP 队头阻塞带来的影响,只有舍弃 TCP 协议。
HTTP2 主要的问题在于,多个 HTTP 请求在复用一个 TCP 连接,下层的 TCP 协议是不知道有多少个 HTTP 请求的,所以一旦发生了TCP 丢包现象,就会触发 TCP 的重传机制,这样在一个 TCP 连接中的所有 HTTP 请求都必须等待这个丢了的包被重传回来(即如果一个 TCP 包丢失,所有后续的包都需要等待它的重传,先到的数据包不会传递给 HTTP,直到丢失的包重传成功,即使它们包含来自不同流的无关联数据)。

假设包 3 先到达,服务器端必须等待包 2 到达后,才将其和包 3 发送给浏览器。

HTTTP3(基于 QUIC) 真正解决 TCP 队头阻塞

由于 TCP 本身的限制,难以对其进行改变。
所以 HTTP3 选择的替代方法是实现一个全新的传输层协议 QUIC,它运行在不可靠的 UDP 协议之上,但它包括 TCP 的所有特性(可靠性、拥塞控制、流量控制和排序等),且集成了 TLS,不允许未加密的连接。HTTP3 运行在 QUIC 协议之上。
QUIC 的流帧 (Stream Frames) 分别跟踪每个流的字节范围,QUIC 协议知道有自己独立的流。
当服务器端知道包 3 比包 2 早到达,QUIC 查看流 1 的字节范围,发现这个流帧完全遵循流 id 1 的第一个流帧,它可以立即将这些数据提供给浏览器进行处理,然而对于流 id 2,QUIC 确实看到了一个缺口(它还没有接收到字节 0-299,这些字节在丢失的 QUIC 数据包 2 中),它将保存该流帧,直到 QUIC 数据包 2 的重传到达。

GET 请求和 POST 请求的区别?

GET 和 POST 本质上都是 TCP 连接,并无差别,但是由于 HTTP 的规定和浏览器/服务器的限制,导致它们在应用过程中体现出一些不同

HTTP1.0、HTTP1.1、HTTP2 和 HTTP3 协议的介绍?

HTTP1.0

HTTP1.0 实现中,如果需要从服务端获取大量资源,会开启 N 条 TCP 短链接,并行的获取信息。

HTTP1.1

SPDY

HTTP2.0(基于 SPDY 修改)

ltngb

HTTP3.0(基于 QUIC)