HTTP请求方法
HTTP请求由三部分构成
- 请求行
- 首部
- 实体
请求行
请求行基本由请求方法、URL、协议版本组成
GET
- GET方法请求一个指定资源的表示形式,使用GET请求应该只被用于获取数据
- 多用于搜索关键字等无副作用,幂等的场景
HEAD
- HEAD方法请求一个与GET请求的响应相同的响应,但没有响应体
POST
- POST方法用于将实体提交到指定资源,通常导致在服务器上的状态变化或副作用
- 副作用指对服务器上的资源做改变,搜索是无副作用的,注册是副作用的
- POST多用于注册等存在副作用,不幂等的场景
- POST用于添加数据,增加新的数据
PUT
- PUT方法用请求有效载荷替换目标资源的所有当前表示
- 用于修改数据,给什么数据这条数据就被修改成什么数据,这条数据的其他信息都被删除掉了
DELETE
- DELETE方法删除指定资源
CONNECT
- CONNECT方法建立一个到由目标资源标识的服务器的隧道
OPTIONS
- OPTIONS方法用于描述目标资源的通信选项
TRACE
- TRACE方法沿着目标资源的路径执行一个消息环回测试
PATCH
- PATCH方法用于对资源应用部分修改,
- 顾名思义打补丁,只修改传入的内容
GET和POST的区别
- GET请求能缓存,POST不能
- POST相对GET安全一点点,因为GET请求都包含在URL里(或者Body),且会被浏览器保存历史记录。POST不会,但是在抓包的情况下都是一样的
- URL有长度限制,会影响GET请求,但是这个长度限制是浏览器规定的,不是RFC规定的
- POST支持更多的编码类型且不对数据类型限制
首部
首部分为请求首部和响应首部,并且部分首部两种通用,下面介绍一部分的常用首部
通用首部
通用字段 | 作用 |
---|---|
Cache-Control | 控制缓存的行为 |
Connection | 浏览器优先使用的连接类型,比如keep-alive |
Date | 创建报文的时间 |
Pragma | 报文指令 |
Via | 代理服务器相关信息 |
Transfer-Encoding | 传输编码方式 |
Upgrade | 要求客户端升级协议 |
Warning | 在内容中可能存在错误 |
请求首
通用字段 | 作用 |
---|---|
Accept | 能正确接收的媒体类型 |
Accept-Charset | 能正确接收的字符集 |
Accept-Encoding | 能正确接收的编码格式列表 |
Accept-Language | 能正确接收的语言列表 |
Expect | 期待服务端的指定行为 |
From | 请求方邮箱地址 |
Host | 服务器的域名 |
If-Match | 两端资源标记比较 |
If-Modified-Since | 本地资源未修改返回304(比较时间) |
If-None-Match | 本地资源未修改返回304(比较标记) |
User-Agent | 客户端信息 |
Max-Forwards | 限制可被代理及网关转发的次数 |
Proxy-Authorization | 向代理服务器发送验证码信息 |
Range | 请求某个内容的一部分 |
Referer | 表示浏览器所访问的前一个页面 |
TE | 传输编码方式 |
响应首部
响应首部 | 作用 |
---|---|
Accept-Ranges | 是否支持某些种类的范围 |
Age | 资源在代理缓存中存在的时间 |
ETag | 资源标识 |
Location | 客户端重定向到某个URL |
Proxy-Authenticate | 向代理服务器发送验证信息 |
Server | 服务器名字 |
WWW-Authenticate | 获取资源需要的验证信息 |
实体首部
实体首部 | 作用 |
---|---|
Allow | 资源的正确请求方式 |
Content-Encoding | 内容的编码格式 |
Content-Language | 内容使用的语言 |
Content-Length | request body 长度 |
Content-Location | 返回数据的备用地址 |
Content-MD5 | Base64加密格式的内容 MD5检验值 |
Content-Range | 内容的位置范围 |
Content-Type | 内容的媒体类型 |
Expires | 内容的过期时间 |
Last_modified | 内容的最后修改时间 |
常见状态码
- 状态码表示了响应的一个状态,可以让我们清晰地了解这一次请求是成功还是失败,如果失败的话,是什么原因导致的,当然状态码也是用于传达语义的。不要胡乱使用状态码。
2XX成功
- 200 OK,表示从客户端发来的请求在服务器端被正确处理
- 204 NO content ,表示请求成功,但响应报文不含实体的主体部分
- 205 Reset Content 表示请求成功,但响应报文不含实体的主体部分,但是与204响应不同在于要求请求方重置内容
- 206 Pratial Content 进行范围请求
3XX重定向
- 301 moved permanently 永久性重定向,表示资源已被分配了新的URL
- 302 found 临时性重定向,表示资源临时被分配了新的URL
- 303 see other,表示资源存在着另一个URL,应使用GET方法获取资源
- 304 not modified 表示服务器允许访问资源,但因发生请求未满足条件的情况
- 307 temporary redirect 临时重定向,和302含义类似,但是期望客户端保持请求方法不变向新的地址发出请求
4XX客户端错误
- 400 Bad request 请求报文存在语法错误
- 401 unauthorized 表示发送的请求需要通过HTTP认证的认证信息
- 403 foribidden 表示对请求资源的访问被服务器拒绝
- 404 not found 表示在服务器上没有找到请求的资源
5XX服务器错误
- 500 Internal serve error 表示服务器端在执行请求时发生了错误
- 501 Not Implemented 表示服务器不支持当前请求所需要的某个功能
- 503 service unavailable 表明服务器暂时处于超负载或者正在停机维护,无法处理请求
TLS 安全传输层协议 (Transport Layer Security)
- TLS 协议位于传输层之上,应用层之下。首次进行 TLS 协议传输需要两个 RTT ,接下来可以通过 Session Resumption 减少到一个 RTT。
- 在 TLS 中使用了两种加密技术,分别为:对称加密和非对称加密。
对称加密
-
对称加密就是两边拥有相同的秘钥,两边都知道如何将密文加密解密
-
这种加密方式固然很好,但是问题就在于如何让双方知道秘钥。因为传输数据都是走的网络,如果将秘钥通过网络的方式传递的话,一旦秘钥被截获就没有加密的意义的。
非对称加密:
- 有公钥私钥之分,公钥所有人都可以知道,可以将数据用公钥加密,但是将数据解密必须使用私钥解密,私钥只有分发公钥的一方才知道。
- 这种加密方式就可以完美解决对称加密存在的问题。假设现在两端需要使用对称加密,那么在这之前,可以先使用非对称加密交换秘钥。
- 简单流程如下:首先服务端将公钥公布出去,那么客户端也就知道公钥了。接下来客户端创建一个秘钥,然后通过公钥加密并发送给服务端,服务端接收到密文以后通过私钥解密出正确的秘钥,这时候两端就都知道秘钥是什么了。
TLS握手过程
- 客户端发送一个随机值以及需要的协议和加密方式。
- 服务端收到客户端的随机值,自己也产生一个随机值,并根据客户端需求的协议和加密方式来使用对应的方式,并且发送自己的证书(如果需要验证客户端证书需要说明)
- 客户端收到服务端的证书并验证是否有效,验证通过会再生成一个随机值,通过服务端证书的公钥去加密这个随机值并发送给服务端,如果服务端需要验证客户端证书的话会附带证书
- 服务端收到加密过的随机值并使用私钥解密获得第三个随机值,这时候两端都拥有了三个随机值,可以通过这三个随机值按照之前约定的加密方式生成密钥,接下来的通信就可以通过该密钥来加密解密
- 在 TLS 握手阶段,两端使用非对称加密的方式来通信,但是因为非对称加密损耗的性能比对称加密大,所以在正式传输数据时,两端使用对称加密的方式通信。
端证书的话会附带证书
- 服务端收到加密过的随机值并使用私钥解密获得第三个随机值,这时候两端都拥有了三个随机值,可以通过这三个随机值按照之前约定的加密方式生成密钥,接下来的通信就可以通过该密钥来加密解密
- 在 TLS 握手阶段,两端使用非对称加密的方式来通信,但是因为非对称加密损耗的性能比对称加密大,所以在正式传输数据时,两端使用对称加密的方式通信。
PS:以上说明的都是 TLS 1.2 协议的握手情况,在 1.3 协议中,首次建立连接只需要一个 RTT,后面恢复连接不需要 RTT 了。
- HTTP/2 通过多路复用、二进制流、Header 压缩等等技术,极大地提高了性能,但是还是存在着问题的
- QUIC 基于 UDP 实现,是 HTTP/3 中的底层支撑协议,该协议基于 UDP,又取了 TCP 中的精华,实现了即快又可靠的协议
http发展历程
诞生
**HTTP(**HyperText Transfer Protocol)是万维网(World Wide Web)的基础协议,由Tim Berners-Lee 博士和他的团队在 1989-1991 年间创造出它。WWW是基于**客户机** <=> **服务器**方式 '利用链接跳转站点' 和 '传输超文本标记语言(HTML)' 的技术综合。
WWW在现有的 TCP 和 IP 协议基础之上建立由四部分组成:
-
- 一个用来表示超文本文档的文本格式,超文本标记语言(HTML)
- 一个用来交换超文本文档的简单协议,超文本传输协议(HTTP)
- 一个显示(以及编辑)超文本文档的客户端,即网络浏览器
- 一个服务器用于提供可访问的文档,即httpd 的前身。
http/0.9 - 单行协议
HTTP问世之初并没有作为标准建立,被正式制定为标准是在1996年公布的HTTP/1.0协议。因此,在这之前的协议被称为HTTP/0.9。
HTTP/0.9 极其简单:请求由单行指令构成,以唯一可用方法GET开头,其后跟目标资源的路径(一旦连接到服务器,协议、服务器、端口号这些都不是必须的)
GET/index.html
响应也极其简单,只包含响应文档本身。
<HTML>
这是一个非常简单的 HTML 页面
</HTML>
HTTP/0.9 的响应内容并不包含 HTTP 头,这意味着只有 HTML 文件可以传送,无法传输其他类型的文件;也没有状态码或错误代码:一旦出现问题,一个特殊的包含问题描述信息的 HTML 文件将被发回,供人们查看。
http/1.0 -构建可扩展性
随着互联网技术的飞速发展,HTTP协议被使用的越来越广泛,协议本身的局限性已经不能满足互联网功能的多样性。因此,1996年5月HTTP/1.0诞生,其内容和功能都大大增加了。对比与HTTP/0.9,新的版本包含了以下功能:
-
- 在每个请求的GET一行后面添加版本号
- 在response第一行添加状态行,使浏览器能了解请求执行成功或失败,并相应调整行为(如更新或使用本地缓存)。
- 在request和response中添加header的概念,,允许传输元数据,使协议变得非常灵活,更具扩展性。
- 在header中添加content-type以此可以传输除html之外类型的文件
- 在header中添加content-encoding来支持不同编码格式文件的传输
- 引入了POST和HEAD命令
- 支持长链接
GET /index.html HTTP/1.0
User-Agent: NCSA_Mosaic/2.0 (Windows 3.1)
200 OK
Date: Tue, 15 Nov 1994 08:12:31 GMT
Server: CERN/3.0 libwww/2.17
Content-Type: text/html;charset=utf-8 // 类型,编码。
<HTML>
A page with an image
<IMG src="/image.gif">
<HTML>
Content
简单的文字页面自然无法满足用户的需求,于是1.0加入了更多的文件类型
-
- text/plan :纯文本格式
- text/html: htm格式
- text/css 、 text/xml
- image.jpeg 、 image/png 、image/svg+xml 图片格式
- application/javascript、application/zip 、application/pdf
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
Content-Encoding
由于支持任意数据格式的发送,因此可以先把数据进行压缩再发送。HTTP/1.0进入了Content-Encoding来表示数据的压缩方式。
-
- Content-Encoding:gizp。表示采用Lempel-Ziv coding (LZ77)压缩算法,以及32位校验的编码方式
- Content-Encoding:compress 。采用Lempel-Ziv-Welch(LZW)压缩算法
- Content-Encoding:deflate。采用zlib
客户端发送请求带有表明我可以接受gzip、deflate两种压缩方式
Accept-Encoding: gzip, deflate
服务器在Content-Encoding响应收不提供了实际采用的压缩模式
Content-Encoding: gzip
http1.0缺点
- 队头阻塞(Head-of-Line Blocking),每个TCP连接只能发送一个请求,发送数据完毕,连接就关闭,如果还要请求其他资源,就必须新建一个连接
- 默认是短连接,客户端和服务器每进行一次 HTTP 操作,就建立一次连接,任务结束就中断连接。当客户端浏览器访问的某个 HTML 或其他类型的 Web 页中包含有其他的 Web 资源(如 JavaScript 文件、图像文件、CSS 文件等),每遇到这样一个 Web 资源,浏览器就会重新建立一个 TCP 连接,这样就会导致有大量的“握手报文”和“挥手报文”占用了带宽,每个HTTP请求都要使用TCP协议通过三次握手和四次握手实现
- 仅定义了16种状态码
http/1.1 - 标准化的协议
仅仅在HTTP/1.0公布后的几个月,HTTP/1.1发布了,到目前为止HTTP1.1协议都是作为主流的版本,以至于随后的近10年时间里都没有新的HTTP协议版本发布
- 连接可以复用(keep-alive),节省了多次打开 TCP 连接加载网页文档资源的时间。
- 增加管线化技术(Pipeline),允许在第一个应答被完全发送之前就发送第二个请求,以降低通信延迟。
- chunked机制,支持响应分块。
- 引入额外的缓存控制机制。
- 引入内容协商机制,包括语言,编码,类型等,并允许客户端和服务器之间约定以最合适的内容进行交换。
- 凭借Host头,能够使不同域名配置在同一个 IP 地址的服务器上。
keep-alive
由于建立一个连接的过程需要DNS解析过程以及TCP的三次握手,但在同服务器获取资源不断的建立和断开链接需要消耗的资源和时间是巨大的,为了提升连接的效率 HTTP/1.1的及时出现将长连接加入了标准并作为默认实现,服务器端也按照协议保持客户端的长连接状态,一个服务端上的多个资源都可以通过这一条连接多个request来获取。
可以在request header中引入如下信息来告知服务器完成一次request请求后不要关闭连接。
Connection:keep-alive
服务器端也会答复一个相同的信息表示连接仍然有效,但是在当时这只是属于程序员的自定义行为,在1.0中没有被纳入标准。这其中的提升对于通讯之间的效率提升几乎是倍增的,为管线化打下基础
pipeline(管线化)
HTTP/1.1尝试通过HTTP管线化技术来解决性能瓶颈,诞生了pipeline机制,如图从每次response返回结果才能进行下一次request,变为一次连接上多个http request不需要等待response就可以连续发送的技术。
不幸的是因为HTTP是一个无状态的协议,一个体积很大的或慢response仍然会阻塞后面所有的请求,每条request无法知道哪条response是返回给他的,服务端只能根据顺序来返回response,这就是队头阻塞,这导致主流浏览器上默认下该功能都是关闭状态,在http2.0中会解决这个问题。
host头域
在 HTTP1.0 中认为每台服务器都绑定一个唯一的 IP 地址,因此,请求消息中的 URL 并没有传递主机名(hostname),1.1中新增的host用来处理一个 IP 地址上面多个虚拟主机的情况。
在请求头域中新增了Host字段,其用来指定服务器的域名。有了Host字段,在同一台服务器上就可以搭建不同的网站了,这也为后来虚拟化的发展建好了地基。Host: www.demo.com
cache机制
缓存
Cache不仅可以提高用户的访问速率,在移动端设备上还可以为用户极大节省流量。因此,在HTTP/1.1中新增了很多与Cache相关的头域并围绕这些头域设计了更灵活、更丰富的Cache机制。
Cache机制需要解决的问题包括:
-
- 判断哪些资源可以被Cache及访问策略
- 在本地判断Cache资源是否已经过期
- 向服务端发起询问,查看已过期的Cache资源是否在服务端发生了变化
chunked机制
建立好链接之后客户端可以使用该链接发送多个请求,用户通常会通过response header中返回的Content-Length来判断服务端返回数据的大小。但随着网络技术的不断发展,越来越多的动态资源被引入进来,这时候服务端就无法在传输之前知道待传递资源的大小,也就无法通过Content-Length来告知用户资源大小。服务器可以一边动态产生资源,一边传递给用户,这种机制称为“分块传输编码”(Chunkded Transfer Encoding),允许服务端发送给客户端的数据分为多个部分,此时服务器端需要在header中添加“Transfer-Encoding: chunked”头域来替代传统的“Content-Length。
HTTP缓存机制
- 强缓存、协商缓存、Expires、ETag、Last-Modified。。。
新增请求方法及状态码
- OPTIONS:浏览器为确定跨域请求资源的安全做的预请求
- PUT:从客户端向服务器传送的数据取代指定的文档的内容
- DELETE :请求服务器删除指定的页面
- TRACE:回显服务器收到的请求,主要用于测试或诊断
- CONNECT:HTTP/1.1 协议中预留给能够将连接改为管道方式的代理服务器
HTTP/1.0缺陷
- 高延迟带来页面加载速度的降低。网络延迟问题主要由于队头阻塞导致宽带无法被充分利用
- 无状态带来巨大的http头部
- 明文传输不安全
- 不支持服务器推送消息
http/2 - 为了更优异的表现
根据时代的发展网页变得更加复杂。其中一些甚至本身就是应用程序。显示了更多的视觉媒体,增加了交互性的脚本的数量和大小也增加了。更多的数据通过更多的 HTTP 请求传输,这为 HTTP/1.1 连接带来了更多的复杂性和开销。为此,谷歌在 2010 年代初实施了一个实验性协议 SPDY。鉴于SPDY的成功,HTTP/2也采用了SPDY作为整个方案的蓝图进行开发。HTTP/2 于 2015 年 5 月正式标准化。
(SPDY(读作“SPeeDY”)是Google开发的基于TCP的会话层 [1] 协议,用以最小化网络延迟,提升网络速度,优化用户的网络使用体验,SPDY并不是一种用于替代HTTP的协议,而是对HTTP协议的增强。新协议的功能包括数据流的多路复用、请求优先级以及HTTP报头压缩)
http/2与http/1.1的区别
- 二进制帧层,不再可读,也不可无障碍的手动创建,改善的优化技术现在可被实施
- 多路复用协议,可以通过同一连接发出并行请求,从而消除HTTP/1.x协议的约束
- 头部压缩算法HPACK,由于一些请求在一组请求中通常是相似的,因此消除了传输数据的重复和开销
- 其允许服务器在客户端缓存中填充数据,通过一个叫服务器推送的机制来提前请求。
一张图来表示
Header压缩
HTTP1.x的header带有大量信息,而且每次都要重复发送,为 HTTP/2 的专门量身打造的 HPACK 便是类似这样的思路延伸。它使用一份索引表来定义常用的 HTTP Header,通讯双方各自cache一份header fields表,既避免了重复header的传输,又减小了需要传输的大小。
看上去协议的格式和HTTP1.x完全不同了,实际上HTTP2并没有改变HTTP1.x的语义,只是把原来HTTP1.x的header和body部分用frame重新封装了一层而已。
多路复用
为了解决HTTP/1.x中存在的队头阻塞问题,HTTP/2提出了多路复用的概念。即将一个request/response作为一个stream,并将一个流stream根据负载分为多种类型的frame(例如 header frame,data frame等),在同一条connection之上可以混合发送分属于不同stream的frame,这样就实现了同时发送多个request的功能,多路复用意味着线头阻塞将不再是一个问题。
HTTP/2 虽然通过多路复用解决了 HTTP 层的队头阻塞,但仍然存在 TCP 层的队头阻塞
流
服务器和客户端在HTTP/2连接内用于交换帧数据的独立双向序列,HTTP/2 在单个 TCP 连接上虚拟出多个 Stream, 多个 Stream 实现对一个 TCP 连接的多路复用, 为了合理地利用传输链路, 实现在有限资源内达到传输性能的最优化。
- 所有的通信都建立在一个TCP连接上,可以传递大量的双向流通的流
- 每个流都有独一无二的标志和优先级
- 每个消息都是逻辑上的请求和相应消息。由一个或者多个帧组成
- 来自不同流的帧可以通过帧头的标志来关联和组装起来
流的概念提出是为了实现多路复用,在单个连接上实现同时进行多个业务单元数据的传输
二进制帧层
在HTTP/1.x中,用户为了提高性能建立多个TCP连接.会导致队头阻塞和重要TCP连接不能稳定获得。HTTP/2中的二进制帧层允许请求和响应数据分割为更小的帧,并且它们采用二进制编码(http1.0基于文本格式)。多个帧之间可以乱序发送,根据帧首部的流(比如每个流都有自己的id)表示可以重新组装。
显然这对二进制的计算机是非常友好,无需再将收到明文的报文转成二进制,而是直接解析二进制报文,进一步提高数据传输的效率。
每一个帧可看做是一个学生,流是小组(流标识符为帧的属性值),一个班级(一个连接)内学生被分为若干个小组,每一个小组分配不同的具体任务,多个小组任务可同时并行在班级内执行。一旦某个小组任务耗时严重,但不会影响到其它小组任务正常执行。
缺点
- TCP以及TCOP+YTS建立连接的延迟(握手延迟)
- http2.0中TCO的队头阻塞依旧没有彻底解决,连接双方的有一个数据包丢失,或任一方的网络终端,整个TCP连接就会暂停,丢失的数据包需要被重新传输,从而阻塞该TCP连接中的所有请求,反而在网络较差或不稳定的情况下,使用多个连接表现更好
http/3
在限定条件下,TCP下解决队头阻塞的问题相当困难,但是随着互联网的爆炸式发展,更高的稳定性和安全性需要得到满足,谷歌在2016年11月国际互联网工程任务组(IETF)召开了第一次QUIC(Quick UDP Internet Connections)工作组会议,制定的一种基于UDP的低时延的互联网传输层协议,HTTP-over-QUIC于2018年11月更名为HTTP/3。
0-RTT握手
Tcp中客户端发送syn包(syn seq=x)到服务器, 服务器接收并且需要发送(SYN seq =y; ACK x+1)包给客户端,客户端向服务器发送确认包ACK(seq = x+1; ack=y+1),至此客户端和服务器进入已确认状态,完成三次握手。
1-RTT
- 客服端生成一个随机数 a 然后选择一个公开的加密数 X ,通过计算得出 a*X = A, 将X 和 A发送给服务端
- 客服端生成一个随机数 b,通过计算得出 b*X = B, 将B发送给服务端
- 客户端使用ECDH生成通讯密钥 key = aB* = a(bX)
- 服务器使用ECDH生成通讯密钥 key = bA* = b(aX)
所以,这里的关键就是 ECDH 算法,a 和 b 是客户端和服务器的私钥,是不公开的,即使知道 A、X,通过 A = a*X 公式也是无法推导出 a 的,保证了私钥的安全性。
0-RTT
0-RTT则是客户端缓存了 ServerConfig(B=b*X),下次建连直接使用缓存数据计算通信密钥
- 客户端:生成随机数 c,选择公开的大数 X,计算 A=cX,将 A 和 X 发送给服务器,也就是 Client Hello 消息后,客户端直接使用缓存的 B 计算通信密钥 KEY = cB = cbX,加密发送应用数据
- 服务器:根据 Client Hello 消息计算通信密钥 key = bA = b(c*X)
客户端不需要经过握手直接通过缓存的B生成key就可以发送应用数据,假设攻击者记录下所有的通信数据和公开参数A1,A2,一旦服务器的随机数 b(私钥)泄漏了,那之前通信的所有数据就都可以破解了。
为了解决这个问题,需要为每次会话都创建一个新的通信密钥,来保证前向安全性。
有序交付
QUIC 是基于 UDP 协议的,而 UDP 是不可靠传输协议,QUIC 在每个数据包都设有一个 offset 字段(偏移量),接收端根据 offset 字段就可以对异步到达的数据包进行排序了,保证了有序性。
sequenceDiagram
客服端->>服务端: PKN=1;offset=0
客服端->>服务端: PKN=2;offset=1
客服端->>服务端: PKN=3;offset=2
服务端-->>客服端: SACK = 1,3
客服端->>服务端: 重传:PKN=4;offset=1
队头堵塞
HTTP/2 之所以存在 TCP 层的队头阻塞,是因为所有请求流都共享一个滑动窗口,而QUIC中给每个请求流都分配一个独立的滑动窗口。
A 请求流上的丢包不会影响 B 请求流上的数据发送。但是,对于每个请求流而言,也是存在队头阻塞问题的,也就是说,虽然 QUIC 解决了 TCP 层的队头阻塞,但仍然存在单条流上的队头阻塞。这就是 QUIC 声明的无队头阻塞的多路复用。
连接迁移
连接迁移:当客户端切换网络时,和服务器的连接并不会断开,仍然可以正常通信,对于 TCP 协议而言,这是不可能做到的。因为 TCP 的连接基于 4 元组:源 IP、源端口、目的 IP、目的端口,只要其中 1 个发生变化,就需要重新建立连接。但 QUIC 的连接是基于 64 位的 Connection ID,网络切换并不会影响 Connection ID 的变化,连接在逻辑上仍然是通的。
假设客户端先使用 IP1 发送了 1 和 2 数据包,之后切换网络,IP 变更为 IP2,发送了 3 和 4 数据包,服务器根据数据包头部的 Connection ID 字段可以判断这 4 个包是来自于同一个客户端。QUIC 能实现连接迁移的根本原因是底层使用 UDP 协议就是面向无连接的。
最后一张图来看下http的升级