什么是HTTP
- http超文本传输协议,位于应用层的、无状态的网络协议。
HTTP无状态
- http服务器不保存客户的信息
HTTP长连接和短连接
-
HTTP长连接:在
HTTP/1.0
中,默认使用的是短连接。浏览器每发起一次HTTP
请求,就建立一个连接,但任务结束就中断连接。 -
HTTP短连接:从
HTTP/1.1
起,默认使用长连接,用以保持连接特性。使用长连接的HTTP协议,会在请求头加上Connection:keep-Alive
字段。长连接模式下,当一个客户端的请求与服务端建立连接后,这个连接并不会在服务端响应结果后立马关闭。HTTP/1.0
中默认关闭,需要手动在请求头中添加Connection: Keep-Alive
才可开启,HTTP/1.1
默认开启,可以手动添加Connection: close
关闭。
HTTP/TCP的 Keepalive
-
HTTP 的 Keep-Alive 也叫 HTTP 长连接,该功能是由「应用程序」实现的,可以使得用同一个 TCP 连接来发送和接收多个 HTTP 请求/应答,减少了 HTTP 短连接带来的多次 TCP 连接建立和释放的开销。
-
TCP 的 Keepalive 也叫 TCP 保活机制,该功能是由「内核」实现的,当客户端和服务端长达一定时间没有进行数据交互时,内核为了确保该连接是否还有效,就会发送探测报文,来检测对方是否还在线,然后来决定是否要关闭该连接。
什么时候用长连接,短连接?
- 长连接多用于操作频繁,点对点的通讯,而且连接数不能太多情况。。例如:数据库的连接用长连接, 如果用短连接频繁的通信会造成socket错误,而且频繁的socket 创建也是对资源的浪费。
- 短连接用于并发量大,但每个用户无需频繁操作情况下。例如:WEB网站的http服务一般都用短链接,因为长连接对于服务端来说会耗费一定的资源,而像WEB网站这么频繁的成千上万甚至上亿客户端的连接用短连接会更省一些资源,如果用长连接,而且同时有成千上万的用户,如果每个用户都占用一个连接的话,服务器承受不住。
HTTP报文格式
ASCII格式
HTTP请求报文:
-
请求行:请求方法+请求目标(URL)+HTTP版本
GET / HTTP/1.1
-
请求头:
Host
:表示客户端访问的目标资源所在的主机,即域名,如www.baidu.com
。User-agent
:浏览器类型Accept
:对应服务端Content-Type
Cookie
:对应客户端Set-cookie
Cache-Control
:控制缓存的相关信息。If-None-Match
: 用于判断资源的缓存是否有效。Connection
:告诉服务器,发送完报文TCP连接关闭/保持。keep-alive/close
-
请求体(实体)
HTTP响应报文:
- 状态行:版本+状态码+状态信息(Reason)
HTTP/1.1 200 OK
- 响应头:
Date
:服务器封装对象并发送响应报文的时间。Last-Modified
:对象创建或最后修改的时间。Content-Type
:实体中对象类型。对应客户端的Accept
Content-Length
:HTTP 协议通过设置回车符、换行符作为 HTTP header 的边界,通过 Content-Length 字段作为 HTTP body 的边界,这两个方式都是为了解决“粘包”的问题。Set-cookie
:对应客户端Cookie
Location
:告诉客户端资源的重定向位置/(URL)路径。Cache-Control
:控制缓存的相关信息。Etag
:用于协商缓存,返回一个摘要值。Connection
:告诉客户,发送完报文TCP连接关闭/保持。keep-alive/close
- 响应体(实体)
HTTP请求方法
-
GET:请求体为空。【幂等】
-
POST:使用请求体。
-
HEAD:类似get,服务器会发出http响应报文,但不返回请求对象,仅有HTTP的头信息【幂等】
-
PUT:允许用户上传对象到服务器。【幂等】
-
DELETE:允许用户删除服务器上的对象。【幂等】
GET/POST比较:
-
GET使用URL显式传参,而POST将数据放在请求体中。
-
GET
请求的资源默认会被浏览器缓存,下次请求相同资源会直接从本地中读取,而POST
请求的资源默认情况下不会缓存。 -
GET方式提交的数据有长度限制,
GET
通常情况下受到浏览器和服务器的限制。则POST的数据则没有限制。 -
POST比GET安全,因为数据在地址栏上不可见。
-
**本质区别:**GET和POST最大的区别主要是GET请求是幂等性的,POST请求不是。
幂等性是指一次和多次请求某一个资源应该具有同样的副作用。简单来说意味着对同一URL的多个请求应该返回同样的结果。
get和post性能对比:get比post更快:post在真正接受数据之前会先将请求头发送给服务器进行确认,然后才真正发送数据
- post请求的过程**:**
-
浏览器请求tcp连接(第一次握手)
-
服务器答应进行tcp连接(第二次握手)
-
浏览器确认,并发送post请求头(第三次握手,这个报文比较小,所以http会在此时进行第一次数据发送)
-
服务器返回100 continue响应
-
浏览器开始发送数据
-
服务器返回200 ok响应
- get请求的过程
-
浏览器请求tcp连接(第一次握手)
-
服务器答应进行tcp连接(第二次握手)
-
浏览器确认,并发送get请求头和数据(第三次握手,这个报文比较小,所以http会在此时进行第一次数据发送)
-
服务器返回200 ok响应
HTTP状态码
-
1xx:提示信息
- 100:
-
2xx:服务器成功处理了客户端的请求
- 200 OK:表示请求在被正常处理。
-
3xx:重定向。
- 301 Moved Permanently:永久重定向,表示请求的对象已经被永久转移了,新的 URL 定义在 响应报文的 Location 字段中,浏览器将自动获取新的 URL。
- 302 Found:临时重定向(即以后还可能有变化),表示请求的资源已被临时分配了新的URL,新的URL 会在响应报文中的 Location 字段中返回
- 304 Not Modified:告诉客户端可以继续使用缓存资源
-
4xx:客户端发送的报文有误
- 「400 Bad Request」:示请求报文中存在语法错误。
- 「403 Forbidden」表示服务器虽然收到了请求,但是拒绝提供服务,常见的原因是为没有访问权 限(即用户未授权)。
- 「404 Not Found」表示请求资源不存在。
-
5xx:服务器处理时内部发生了错误
- 「500 Internal Server Error」表示服务器出现错误,可能是出现了一些 Bug 或故障。
- 「502 Bad Gateway」通常是服务器作为网关或代理时返回的错误码,表示服务器自身工作正常,访问后端服务器发生了错误。
- 「503 Service Unavailable」表示服务器当前很忙,暂时无法响应客户端,类似“网络服务正忙,请稍后重试”的意思。
- 502是网关错误,504是网关超时。502是代理服务器后面的真实服务器节点配置出了问题或者已经挂掉了,而504是代理服务器后面的真实服务器已经过载,它要处理的请求报文实在太多,忙不过来了
502问题排查:https://juejin.cn/post/7155280646112280613
- HTTP状态码用来表示响应结果的状态,其中200是正常响应,4xx是客户端错误,5xx是服务端错误。
- 客户端和服务端之间加入nginx,可以起到反向代理和负载均衡的作用,客户端只管向nginx请求数据,并不关心这个请求具体由哪个服务器来处理。
- 后端服务端应用如果发生崩溃,nginx在访问服务端时会收到服务端返回的RST报文,然后给客户端返回502报错。502并不是服务端应用发出的,而是nginx发出的。因此发生502时,后端服务端很可能没有没有相关的502日志,需要在nginx侧才能看到这条502日志。
- 如果发现502,优先通过监控排查服务端应用是否发生过崩溃重启,如果是的话,再看下是否留下过崩溃堆栈日志,如果没有日志,看下是否可能是oom或者是其他原因导致进程主动退出。如果进程也没崩溃过,去排查下nginx的日志,看下是否将请求打到了某个不知名IP端口上。
RST发送原因:
-
服务端设置的超时时间过短:服务端在收到请求后需要在
2s
内处理完并将结果写到响应中,如果等不到,就会将连接给断掉。 -
服务端应用进程崩了(crash)
-
# ps -o lstart 13515 //查看进程上次启动时间 STARTED Wed Aug 31 14:28:53 2022
Cookie和Session和token:
HTTP请求报文和响应报文中都有一个Cookie首部行。
-
**cookie:**服务器发送到浏览器并保存在本地的一小块数据。浏览器之后向同一服务器再次发送请求时候被携带上,告知服务端两个请求来自同一浏览器。
-
**session:**session 是另一种记录服务器和客户端会话状态的机制。session 是基于 cookie 实现的,session 存储在服务器端,sessionId 会被存储到客户端的cookie 中。
-
**token:**访问资源接口(API)时所需要的资源凭证。简单 token 的组成: uid(用户唯一的身份标识)、time(当前时间的时间戳)、sign(签名,token 的前几位以哈希算法压缩成的一定长度的十六进制字符串)。
-
Cookie工作流程:
-
浏览器发起HTTP请求报文
-
服务器用一个包含Set-Cookie首部的响应报文进行响应
Set-cookie:1678
-
浏览器在它管理的cookie文件中添加一行:主机名+Set-cookie:1678
-
当浏览器下次再次访问时,会查询cookie文件,HTTP请求报文包含Cookie首部。
Cookie:1678
-
-
session工作流程:
- 用户第一次请求服务器的时候,服务器根据用户提交的相关信息,创建对应的 Session。
- 请求返回时将此 Session 的唯一标识信息 SessionID 返回给浏览器
- 浏览器接收到服务器返回的 SessionID 信息后,会将此信息存入到 Cookie 中,同时 Cookie 记录此 SessionID 属于哪个域名
- 当用户第二次访问服务器的时候,请求会自动判断此域名下是否存在 Cookie 信息,如果存在自动将 Cookie 信息也发送给服务端,服务端会从 Cookie 中获取 SessionID,再根据 SessionID 查找对应的 Session 信息,如果没有找到说明用户没有登录或者登录失效,如果找到 Session 证明用户已经登录可执行后面操作。
-
**token工作流程:**类似于cookie
- 客户端使用用户名跟密码进行登录验证。
- 验证成功后,服务端会生成加密的token并返回给客户端。
- 客户端收到 token 以后,会把它存储起来,比如放在 cookie 里或者 localStorage 里。
- 客户端下次携带token发起请求。
- 服务端收到请求,然后去验证客户端请求里面带着的 token ,如果验证成功,就向客户端返回请求的数据。
-
有了 Cookie 为什么还需要 Token?
- cookie的跨域限制问题,相较于Cookie,token需要自己存储,自己进行发送,不存在跨域限制。cookie 是不可跨域的: 每个 cookie 都会绑定单一的域名,无法在别的域名下获取使用,一级域名和二级域名之间是允许共享使用的(靠的是 domain)。
- token安全性更高。
- Cookie 存储的内存空间只有 4kb。所有用户都需要在服务器的 Session 中存储相对应的用户信息,压力大。Token 没有内存限制,Token 将用户信息返回给客户端各自存储。
跨域问题:跨域问题指的是不同站点之间,使用 ajax 无法相互调用的问题。
- 协议不同,如 http 和 https;
- 域名不同;
- 端口不同。
-
Cookie和Session对比:
- 安全性: Session 比 Cookie 安全,Session 是存储在服务器端的,Cookie 是存储在客户端的。
- 存取值的类型不同:Cookie 只支持存字符串数据,想要设置其他类型的数据,需要将其转换成字符串,Session 可以存任意数据类型。
- 有效期不同: Cookie 可设置为长时间保持,比如我们经常使用的默认登录功能,Session 一般失效时间较短,客户端关闭(默认情况下)或者 Session 超时都会失效。
- 存储大小不同: 单个 Cookie 保存的数据不能超过 4K,Session 可存储数据远高于 Cookie,但是当访问量过多,会占用过多的服务器资源。
Http缓存
协商缓存这两个字段都需要配合强制缓存中 Cache-control 字段来使用,只有在未能命中强制缓存的时候,才能发起带有协商缓存字段的请求
首先通过 Cache-Control / expire
验证强缓存是否可用,如果强缓存可用,那么直接读取缓存
如果不可以,那么进入协商缓存阶段,发起 HTTP 请求,服务器通过请求头中是否带上 If-Modified-Since & Last-Modified
和 If-None-Match & Etag
这些条件请求字段检查资源是否更新:
- 若资源更新,那么返回资源和 200 状态码
- 如果资源未更新,那么告诉浏览器直接使用缓存获取资源,返回
304 not modified
-
强制缓存:
200 from disk cache
-
强缓存是利用下面这两个 HTTP 响应头部(Response Header)字段实现的:
-
Cache-Control
, 是一个相对时间; -
Expires
,是一个绝对时间;
-
-
当浏览器第一次请求访问服务器资源时,服务器会在返回这个资源的同时,在 Response 头部加上 Cache-Control,Cache-Control 中设置了过期时间大小;
-
浏览器再次请求访问服务器中的该资源时,会先通过请求资源的时间与 Cache-Control 中设置的过期时间大小,来计算出该资源是否过期,如果没有,则使用该缓存,否则重新请求服务器;
-
服务器再次收到请求后,会再次更新 Response 头部的 Cache-Control。
-
-
协商缓存:
-
协商缓存可以基于两种头部来实现:
-
请求头部中的
If-Modified-Since
字段与响应头部中的Last-Modified
字段实现:- 在客户端第一次请求的时候,服务器会返回资源最后的修改时间,记作Last-Modified。客户端将这个字段连同资源缓存起来。Last-Modified被保存以后,在下次请求时会以Last-Modified-Since字段被发送。
- 当客户端再次请求服务器时,会把Last-Modified连同请求的资源一起发给服务器,这是Last-Modified会被命名为If-Modified-Since,存放的内容都是一样的。 服务器收到请求,会把If-Modified-Since字段与服务器上保存的Last-Modified字段作比较。若服务器上的Last-Modified最后修改时间大于请求的If-Modified-Since,说明资源被改动过,就会把资源(包括Header +Body)重新返回给浏览器,同时返回状态码200;若资源的最后修改时间小于或等于If-Modified-Since,说明资源没有改动过,只会返回Header,并且返回状态码304。浏览器接受到这个消息就可以使用本地缓存库的数据
-
请求头部中的
If-None-Match
字段与响应头部中的ETag
字段:- 客户端第一次请求的时候,服务器会给每个资源生成一个ETag标记。这个ETag是根据每个资源生成的唯一Hash串,资源如何发生变化ETag随之更改,之后将这个ETag返回给客户端,客户端把请求的资源和ETag都缓存到本地。ETag被保存以后,在下次请求时会当作If-Noe-Match 字段被发送出去。
- 在浏览器第二次请求服务器相同资源时,会把资源对应的ETag一并发送给服务器。在请求时ETag转化成If-None-Match,但其内容不变。服务器收到请求后,会把 If-None-Match与服务器上资源的ETag进行比较。如果不一致,说明资源被改动过,则返回资源(Header+Body),返回状态码200;如果一致,说明资源没有被改过,则返回Header,返回状态码304。浏览器接受到这个消息就可以使用本地缓存库的数据。
- ETag和If-None-Match指的是同一个值,只是在客户端和服务器端的叫法不同。
- Etag 的优先级更高
- 按 F5 刷新或浏览器的刷新按钮,默认加上 Cache-Control:max-age=0,即会走协商缓存
-
-
HTTP和HTTPS
-
http明文传输不安全,https在 TCP 和 HTTP 网络层之间加入了 SSL/TLS 安全协议,使得报文能够加密传输。
HTTP 有以下安全性问题:
-
使用明文进行通信,内容可能会被窃听(HTTPS 采用加密解决);
-
不验证通信方的身份,通信方的身份有可能遭遇伪装(HTTPS 采用 CA 证书解决);
-
无法证明报文的完整性,报文有可能遭篡改(HTTPS 采用摘要算法解决)。
- HTTP 也提供了 MD5 报文摘要功能,但不是安全的。例如报文内容被篡改之后,同时重新计算 MD5 的值,通信接收方是无法意识到发生了篡改。
- HTTPS 的报文摘要功能之所以安全,是因为它结合了加密和认证这两个操作。试想一 下,加密之后的报文,遭到篡改之后,也很难重新计算报文摘要,因为无法轻易获取明文。
-
-
HTTP 连接建立相对简单, TCP 三次握手之后便可进行 HTTP 的报文传输。而 HTTPS 在 TCP 三次 握手之后,还需进行 SSL/TLS 的握手过程,才可进入加密报文传输。
-
HTTP 的端口号是 80,HTTPS 的端口号是 443。
-
HTTPS 协议需要向 CA(证书权威机构)申请数字证书,来保证服务器的身份是可信的,证书授权 需要支付大量费用。
-
HTTPS 需要加密则请求响应速度更慢。
HTTPS的整体过程
HTTPS 的整体过程分为证书验证和数据传输阶段:
- 证书验证阶段:
- 浏览器发起 HTTPS 请求;
- 服务端返回 HTTPS 证书;
- 客户端验证证书是否合法,如果不合法则提示告警。
- 数据传输阶段:
- 当证书验证合法后,在本地生成随机数;
- 通过公钥加密随机数,并把加密后的随机数传输到服务端;
- 服务端通过私钥对随机数进行解密;
- 服务端通过客户端传入的随机数构造对称加密算法,通信双方可用对称密钥来加密解密信息。
HTTPS握手
数字签名: “摘要”就是对传输的内容,通过hash算法计算出一段固定长度的串。然后,通过发送方的私钥对这段摘要进行加密,加密后得到的结果就是“数字签名”
数字证书:公钥+个人信息+数字签名
SSL/TLS 1.2 需要 4 握手,需要 2 个 RTT 的时延。
SSL/TLS 1.3 优化了过程,只需要 1 个 RTT 往返时延,也就是只需要 3 次握手。
TLS/1.2协四次握手:
客户端向服务端发起TCP握手请求,与服务端443端口建立tcp连接。
1. ClientHello
首先,由客户端向服务器发起加密通信请求,也就是 ClientHello
请求。
客户端主要向服务器发送以下信息:
(1)客户端支持的 TLS 协议版本,如 TLS 1.2 版本。
(2)客户端生产的随机数(Client Random
),后面用于生成「会话秘钥」条件之一。
(3)客户端支持的密码套件列表,如 RSA 加密算法。
2. SeverHello
服务器收到客户端请求后,向客户端发出响应,也就是 SeverHello
。服务器回应的内容有如下内容:
(1)确认 TLS 协议版本,如果浏览器不支持,则关闭加密通信。
(2)服务器生产的随机数(Server Random
),也是后面用于生产「会话秘钥」条件之一。
(3)确认的密码套件列表,如 RSA 加密算法。
(4)服务器的数字证书。
3.客户端回应
客户端收到服务器的回应之后,首先通过浏览器或者操作系统中的 CA 公钥,确认服务器的数字证书的真实性。
如果证书没有问题,客户端会从数字证书中取出服务器的公钥,然后使用它加密报文,向服务器发送如下信息:
(1)一个随机数(pre-master key
)。该随机数会被服务器公钥加密。
(2)加密通信算法改变通知,表示随后的信息都将用「会话秘钥」加密通信。
(3)客户端握手结束通知,表示客户端的握手阶段已经结束。这一项同时把之前所有内容的发生的数据做个摘要,用来供服务端校验。
上面第一项的随机数是整个握手阶段的第三个随机数,会发给服务端,所以这个随机数客户端和服务端都是一样的。
服务器和客户端有了这三个随机数(Client Random、Server Random、pre-master key预主密钥),接着就用双方协商的加密算法,各自生成本次通信的「会话秘钥」。
4. 服务器的最后回应
服务器收到客户端的第三个随机数(pre-master key
)之后,通过协商的加密算法,计算出本次通信的「会话秘钥」。
然后,向客户端发送最后的信息:
(1)加密通信算法改变通知,表示随后的信息都将用「会话秘钥」加密通信。
(2)服务器握手结束通知,表示服务器的握手阶段已经结束。这一项同时把之前所有内容的发生的数据做个摘要,用来供客户端校验。
中间人攻击(CA)
中间人攻击:
- 本地请求被劫持(如 DNS 劫持等),所有请求均发送到中间人的服务器;
- 中间人服务器返回中间人自己的证书;
- 客户端创建随机数,通过中间人证书的公钥对随机数加密后传送给中间人,然后凭随机数构造对 称加密对传输内容进行加密传输;
- 中间人因为拥有客户端的随机数,可以通过对称加密算法进行内容解密;
- 中间人以客户端的请求内容再向正规网站发起请求;
- 因为中间人与服务器的通信过程是合法的,正规网站通过建立的安全通道返回加密后的数据;
- 中间人凭借与正规网站建立的对称加密算法对内容进行解密;
- 中间人通过与客户端建立的对称加密算法对正规内容返回的数据进行加密传输;
- 客户端通过与中间人建立的对称加密算法对返回结果数据进行解密。
解决办法:
-
①服务端先在本地生成一对密钥,然后携带公钥、网站信息、企业信息等数据去
CA
机构申请; -
②
CA
机构根据提交的信息核实身份后,会通过单向的哈希算法(如MD5
)对这些信息进行加密,加密后的内容被称为“信息摘要”,因为单向哈希算法的不可逆特性,所以只要被加密的内容发生了丁点改变,加密后得到的内容也会存在天差地别,因此可以有效防止信息被篡改; -
③紧接着
CA
机构会通过自己的密钥对“信息摘要”进行再次加密,加密后的内容被称为「数字签名」,而「申请信息、服务器公钥、数字签名」组合在一起,最终被称为「数字证书」 -
这样只能保证证书的有效性,不被篡改。但仅这样也无法避免公钥被掉包,也就是“第三者”也去
CA
机构申请证书,然后在中间直接将整个证书替换成自己的,最终客户端获取的依旧是“第三者”的公钥。 -
解决方案:
CA
机构颁发的数字证书中,还会涵盖网站信息(如域名、所有者等),当证书被掉包后,客户端发现返回的证书与请求的网站信息并不同,那么依旧会拒绝连接。
原因:
- ①数据遭受篡改。这个问题发生的原因是:客户端没有效验数据完整性,因此对于对端发送的数据无条件信任,最终就导致了客户端无法区分数据究竟是第三者发出来的,还是真正的服务端返回的。
- ②第三者将公钥掉包。这个问题的主要原因在于:客户端没有效验通信对端,即服务端的身份,因此无法区分传回的究竟是服务端,还是第三者的公钥。
RSA算法:
是一种公钥加密算法。
不是绝对安全的,基于一个事实:快速对一个大数机械能质因数分解是一个非常困难的问题。
HTTP1.1/2/3
-
HTTP1.1:
- 管道机制
- 长连接
- 断点续传,实际上就是利用 HTTP 消息头使用分块传输编码,将实体主体分块传输。
**HTTP队头阻塞:**http要求对于请求的处理必须为“一求一应/一发一收”,所以
HTTP
本质上会将请求串行化,所有的请求会被放入到一个队列中依次交由服务器处理,那么假设前面的请求任务执行时间过长,最终就会导致后面的所有请求全部被阻塞解决办法:
- 管线化技术:户端可以同时发出多个 HTTP 请求,而不用⼀个 个等待响应。但是服务器必须按照请求的顺序来响应,即后续请求的响应必须等到第一个响应发送之后才能发送。(实际中不使用)
- **并发连接:**在客户端建立多个连接,可以增加队列数量,一个队列中的请求阻塞,并不会影响其他队列中的请求。
- **域名分片:**一个域名可以支持多个并发连接,可以多准备几个域名,然后域名配置的
IP
映射都指向同一台服务器,这样就可以支持更多的连接了。
-
HTTP2:基于 HTTPS
- 头部压缩:http2.0可以对请求头进行压缩,通过
Content-Encoding
头部字段来指定。 - 二进制分帧:原来
Headers + Body
的报文格式如今被拆分成了一个个二进制的帧,放弃ASCLL码 - 数据流:在 HTTP/2 中每个请求或相应的所有数 据包(将一个 TCP 的连接中,切分成多个流),称为一个数据流(Stream)。每个数据流都标记着 一个独一无二的编号(Stream ID),不同 Stream 的帧是可以乱序发送的(因此可以并发不同的 Stream ),多个 Stream 复用一条 TCP 连接。请求和响应报文被划分为多个帧,帧中有流标识符,可以使得帧在接收方按序重组。
- 多路复用:HTTP/2 可以在一个TCP连接中并发多个请求或回应,而不用按照顺序一一对应。
- 服务器推送:不经请求服务端主动向客户端发送数据。
对头阻塞:
- HTTP/1.1 中的管道( pipeline)机制虽然解决了请求的队头阻塞,但是没有解决响应的队头阻塞,因为服务端需要按顺序响应收到的请求,如果服务端处理某个请求消耗的时间比较长,那么只能等响应完这个请求后, 才能处理下一个请求,这属于 HTTP 层队头阻塞。
- HTTP/2 虽然通过多个请求复用一个 TCP 连接解决了 HTTP 的队头阻塞 ,TCP 因为超时确认或丢包引起的滑动窗口阻塞问题,这属于 TCP 层队头阻塞。。因为 TCP 是字节流协议,TCP 层必须保证收到的字节数据是完整且有序的,如果序列号较低的 TCP 段在网络传输中丢失了,即使序列号较高的 TCP 段已经被接收了,应用层也无法从内核中读取到这部分数据,从 HTTP 视角看,就是请求被阻塞了。
- QUIC 使用的Packet Number 单调递增的设计,可以让数据包不再像TCP 那样必须有序确认,QUIC 支持乱序确认,当数据包Packet N 丢失后,只要有新的已接收数据包确认,当前窗口就会继续向右滑动。待发送端获知数据包Packet N 丢失后,会将需要重传的数据包放到待发送队列,重新编号比如数据包Packet N+M 后重新发送给接收端,对重传数据包的处理跟发送新的数据包类似,这样就不会因为丢包重传将当前窗口阻塞在原地,从而解决了队头阻塞问题。
- 重传的数据包Packet N+M 和丢失的数据包Packet N依靠Stream ID和Stream offset,来判断内容是否一致。
- 有了Stream Offset 字段信息,属于同一个Stream ID 的数据包也可以乱序传输了(HTTP/2 中仅靠Stream ID 标识,要求同属于一个Stream ID 的数据帧必须有序传输),通过两个数据包的Stream ID 与 Stream Offset 都一致,就说明这两个数据包的内容一致
- 头部压缩:http2.0可以对请求头进行压缩,通过
-
HTTP3:
-
无队头阻塞,QUIC 连接上的多个 Stream 之间并没有依赖,都是独立的,也不会有底层协议限制,某个流发生丢包了,只会影响该流,其他流不受影响。因此不存在队头阻塞问题。
-
建立连接速度更快,因为 QUIC 内部包含 TLS1.3,因此仅需 1 个 RTT 就可以「同时」完成建立连接与 TLS 密钥协商,甚至在第二次连接的时候,应用数据包可以和 QUIC 握手信息(连接信息 + TLS 信息)一起发送,达到 0-RTT 的效果。
HTTP/2:发起 HTTP 请求时,需要经过 TCP 三次握手和 TLS 四次握手(TLS 1.2)的过程,因此共需要 3 个 RTT 的时延才能发出请求数据。
-
连接迁移:
基于 TCP 传输协议的 HTTP 协议,通过四元组(源 IP、源端口、目的 IP、目的 端口)确定一条 TCP 连接,这意味着如果 IP 地址或者端口变动了,就会导致需要 TCP 与 TLS 重新握手,这不利于移动设备切换网络的场景,比如 4G 网络环境切换成 WIFI,IP地址改变。
QUIC 协议通过「连接 ID 」来标记通信的两个端点,客户端和服务器可以各自选择一组 ID 来标记自己,因此即使移动设备的网络变化后,导致 IP 地址变化了,只要仍保有上下文信息(比如连接 ID、TLS 密钥等),就可以“无缝”地复用原连接,消除重连的成本;
-