推进网站集约化建设的做法,学校网站开发实际意义,网站代理什么意思,企事业单位社区1.HTTP
当我们浏览网页时#xff0c;地址栏中使用最多的多是https://开头的url#xff0c;它与我们所学的http协议有什么区别#xff1f; http协议又叫超文本传输协议#xff0c;它是应用层中使用最多的协议#xff0c; http与我们常说的socket有什么区别吗#xff1f; …1.HTTP
当我们浏览网页时地址栏中使用最多的多是https://开头的url它与我们所学的http协议有什么区别 http协议又叫超文本传输协议它是应用层中使用最多的协议 http与我们常说的socket有什么区别吗 我们使用的网络可以分为会话层和表示层可以忽略每一层使用下一层的功能并为上一层提供接口我们经常听说的http协议就是应用层的协议其中应用层协议包括ftp等等而应用层还需要使用传输层的协议http使用的就是tcp协议http3计划使用udp协议。不过不管是tcp还是udp都是使用网络层的ip协议。不过传输层及以下层都是在操作系统内核中的不利于我们使用所以在用户态设计了socket接口来帮助我们使用tcp或者udp的网络协议。而http协议则是已经定义好解析标准的能让我们直接使用的协议。 1.1 http1.0 http1.0是个短连接即每发一次请求就建立一次连接一次响应后就释放连接这种方式简化了http的请求响应但是却造成了重大的浪费不能并行请求每次请求都需要建立连接和释放连接导致每次请求都需要三次握手和四次挥手。 1.2 http1.1
http1.1为了优化http1.0加入了很多东西。 ①keep-alive长连接长连接每个连接完成一次请求后先不关闭在一定时间内可以发送多次请求。通过设置请求头Connection: keep-alive来实现http1.1的长连接减少了三次握手和四次挥手的次数不过需要前一次请求的响应返回后才能发送下一次请求但是有个问题在不释放连接的情况下如何才能判断请求已经结束例如浏览器怎么知道数据传输完毕了 通过 Content-Length 的长度信息判断响应数据传输完毕。但是如果是大文件或者动态生成的数据呢这些数据一开始可能不知道它们的长度这时候就需要用到Transfer-Encoding: chunked请求头这个请求头标识需要响应使用数据分块传输并且每个块会有长度和数据如果接收到长度为0的块标识数据接收完毕。http长连接 – http请求与连接的关系 ②pipelining管道化技术虽然长连接减少了握手消耗但是每次都要前一次请求完成之后才能发送下一次请求管道化技术允许在一个请求没有响应之前发送多次请求。不过管道话技术要求响应必须按照请求发送的顺序返回否则无法解析。存在队头阻塞。实际使用不多。 ③增加并发连接数量与多域名http1为了实现多并发增加http连接的数量。 2.HTTPS 上面所说的http协议都是明文传输的而且不会对应用数据和主机进行验证这样即使数据被窃取和篡改我们也不得而知所以为了保证http的安全在它的基础上加了TSL/SSL安全协议。形成了我们所说的https协议。 先盗一张https验证的过程图 信息的安全传输解决三个问题保密性完整性与端点鉴别。 ab为传输方c为攻击方 1.保密性 http之所以不安全最大的原因就是使用明文传输所以加密成了最大的问题目前分为两大类加密算法md5由于不能解密不能算作加密算法 ①对称加密DES(分组加密算法)AES(可以看作是DES的升级版) ②非对称加密RSA、DSA 由于目前公钥加密算法的开销比较大所以一般采用对称加密来保密信息。但是对称加密过程密钥如何传输这时可以使用公私钥来进行传输因为公私钥使用公钥加密私钥解密所以只要是对方公钥加密的数据只有对方的私钥才能解密私钥不公开保证了传输过程中即使数据泄露也没办法解密对应图中④的过程 note不过又出现了一个问题如何保证a得到的是b的公钥而不是别人伪造的这就需要下面的端点鉴别。 2.完整性 为了防止http数据在传输的过程中被篡改完整性也是必须要考虑的问题如何保证信息的完整性。 ①发送方使用自己的私钥加密信息接收方接收到后只能使用发送方的公钥解密 ②使用信息摘要算法md5sha生成散列加在正文数据的后面 第一种方法由于中间人没有发送方的私钥所以只能解密发送传输的数据但是不能修改数据因为一旦中间人修改数据接收方利用发送方的公钥解密得到的数据就是错误的信息中有专门的比特位用于验证信息的正确性但是向前面说的公私钥加密开销比较大所以不建议采用。 信息摘要算法是利用散列函数将信息映射成一段固定长的数据由于该算法具有不可逆性而且不同的数据散列得到的数据基本不会相同。所以接收方得到数据后将正文数据散列得到的数据于散列值比对如果不同则正文数据遭篡改。 3.端点鉴别 保证了数据的完整性和保密性后最终的问题就是如何确定发送方的问题。如何不进行端点鉴别就可能会出现中间人攻击的风险如图端点A和端点B通信但是中间人C拦截了请求并冒充B和A通信中间人C将自己的公钥发给A让A误以为这是B的公钥然后C作为客户端向端点B发请求将A发送的报文解密后用BC之间的共享密钥加密这样A误以为是在和B进行https加密通信但是其实中间人已经知晓所有的报文。那么如何知晓这是公钥是不是B的 这就需要用到证书证书是CA机构用自己的私钥加密后的得到的东西用来证明公钥持有者的身份证书包括以下东西 持有者信息证书认证机构CA的信息CA 对这份文件的数字签名及使用的算法证书有效期以及一些额外信息 CA是权威的受信任的证书颁发机构CA的公钥会内嵌在浏览器中。由于CA使用自己的私钥加密证书所以可以保证证书不可以伪造。服务器在发送公钥的时候还要发送自己的证书客户端解密该证书的时候将证书中的公钥与服务器发来的公钥比较如果两者相同则直接说明服务器发来的公钥是可靠的如果不相同说明服务器端身份有问题。例如上图中间人C将自己的公钥和证书发给端点AA解密证书发现证书中的网站信息与B不同说明访问的端点不是B。 证书分为根证书和中间证书我们我大部分的证书都是由中间CA机构颁发的中间CA机构是受根CA机构信任的能够颁发CA证书的机构这样就形成了一个证书链客户端信任操作系统浏览器-浏览器信任根CA机构-根CA机构信任中间CA机构-中间CA机构信任中间证书。所以浏览器对于收到的多级证书需要从站点证书开始逐级验证直至出现操作系统或浏览器内置的受信任 CA 根证书。 2.1TLS的流程 https是在http的基础上添加tls协议保证安全性的那么tls的过程又是如何呢?SSL/TLS工作原理以及几幅图拿下 HTTPS tls握手的过程这里以比较熟知的RSA密钥交换算法为例说明下面会说明DHE密钥交换算法RSA算法主要分为以下几步 ①Client Hello握手第一步是客户端向服务端发送 Client Hello 消息这个消息里包含了一个客户端生成的随机数 Random1、客户端支持的加密套件Support Ciphers和 SSL Version 等信息。 ②Server Hello第二步是服务端向客户端发送 Server Hello 消息这个消息会从 Client Hello 传过来的 Support Ciphers 里确定一份加密套件这个套件决定了后续加密和生成摘要时具体使用哪些算法另外还会生成一份随机数 Random2。注意至此客户端和服务端都拥有了两个随机数Random1 Random2这两个随机数会在后续生成对称秘钥时用到。 ③Certificate这一步是服务端将自己的证书下发给客户端让客户端验证自己的身份客户端验证通过后取出证书中的公钥。Server Key Exchange如果是DH算法这里发送服务器使用的DH参数。RSA算法不需要这一步。Server Hello Done通知客户端 Server Hello 过程结束。 ④Certificate Verify客户端收到服务端传来的证书后先从 CA 验证该证书的合法性验证通过后取出证书中的服务端公钥再生成一个随机数 Random3再用服务端公钥非对称加密 Random3生成 PreMaster Key。 ⑤Client Key Exchange上面客户端根据服务器传来的公钥生成了 PreMaster KeyClient Key Exchange 就是将这个 key 传给服务端服务端再用自己的私钥解出这个 PreMaster Key得到客户端生成的 Random3。至此客户端和服务端都拥有 Random1 Random2 Random3两边再根据同样的算法就可以生成一份秘钥握手结束后的应用层数据都是使用这个秘钥进行对称加密。为什么要使用三个随机数呢这是因为 SSL/TLS 握手过程的数据都是明文传输的并且多个随机数种子来生成秘钥不容易被暴力破解出来。 ⑥Change Cipher Spec(Client)这一步是客户端通知服务端后面再发送的消息都会使用前面协商出来的秘钥加密了是一条事件消息。Encrypted Handshake Message(Client Finish)客户端将前面的握手消息生成摘要再用协商好的秘钥加密这是客户端发出的第一条加密消息。服务端接收后会用秘钥解密能解出来说明前面协商出来的秘钥是一致的。 ⑦Change Cipher Spec(Server)和Encrypted Handshake Message(Server)与客户端的意思基本相同使用前面的加密数据和加密之前的握手消息。 2.2https的优化
①会话复用tls https为了安全引入了tls但是一次连接无形中又增加了tls握手的部分而且要命的是每次都需要将这个过程走一遍。为了复用TLS过程我们引入了session id与sesson ticket机制 Session会话恢复SessionIDSessionTicket session id是指一次tls握手完成后第一次握手携带空的session id服务器端就知道首次连接服务器端生成session id返回客户端存下而且客户端会将生成的密钥存放在tls层中接着下次连接时客户端携带此session id发起请求服务器端收到后与内存中的session id比较如果相同则使用上次的密钥。发送一个Change Cipher Spec报文后就发送加密后的验证信息Finished。 session ticket与session id的过程差不多但是session ticket为了解决有多台服务器的问题服务器负载均衡导致两次请求到不同机器所以session ticket是首次tls握手完成后服务端将加密协议算法参数等加密生成会话票据服务器不存储传给客户端存储等客户端下次tls握手时服务器验证票据并根据票据生成加密密钥同时生成新的NewSessionTicket防止过期。 ②前向安全算法 普通的密钥交换算法rsa需要使用公私钥传输加密密钥如果私钥一旦泄露那么中间人就可以通过私钥解密出加密密钥当前会话以及后续会话就不安全了。为了安全性设计出了ECDHEDHE算法TLS/SSL 协议中的RSA、ECDHE、ECDH流程与区别。 上面那张图是RSA算法交换加密密钥的过程下面的图则是ECDHE算法交换密钥的过程ECDHE与DHE的过程相同只是加密算法不同而已下面以DHE算法流程为例说明 1客户端发送client hello申请DHE加密。 2服务器允许DHE算法并生成加密使用的参数p,q,然后服务器生成随机数Xb作为自己的临时私钥接着计算Pb q^Xb mod p最后发送sever hello和server key exchange包括Pbp q等加密参数至客户端Xb仅自己保存。 3客户端收到Pb后生成自己的临时私钥Xa接着计算Pa q^Xa mod p然后将Pa发送给服务器端客户端发送client key exchange 包括Pa至服务器 4客户端计算SaPb ^Xa mod p服务器收到Pa后计算Sb Pa^Xb mod pDHE与ECDHE算法使用离散对数的概念保证了Sa与Sb的相同和高度保密性所以密钥交换成功最后双方通过S加解密数据。算法的加密过程可以查看DH密钥交换算法DHE与DH不同的是DHE使用临时的私钥这样可以保证即使一次通信密钥被破解但是其他的通信仍是安全的。 ③TFOtcp fast openTFO详解 传统的http通信需要先进性3次握手后才能发送数据但是为了提高速度一般在第三次握手时会携带应用数据即使服务器没有收到客户端也可以在超时后重发但是每次http通信还是需要浪费1RTT的时间 如图为了弥补这种浪费人们设计出了TFO通信方式在第一次通信时按照正常的3次握手来完成同时第一次通信完成后服务器端会发送cookie给客户端接下来的tcp通信客户端会发送cookie与应用数据这个过程就和上面的tsl复用的思路一样。 如果cookie验证成功则将应用数据上传给应用程序并且服务器端会发送客户端syn和应用数据确认的ack如果cookie验证不成功则服务器会将数据丢弃然后只发送syn确认的ack客户端通过服务器端的ack就可以知道cookie是否验证成功如果不成功则客户端第三次握手的时候再发送一遍应用数据这就又回到了没有TFO的过程。 ④hstsHTTP Strict-Transport-SecurityHSTS详解-CSDN博客 在访问网站的时候我们经常会直接敲域名www.baidu.com而不会添加http://或者https://而浏览器为了兼容http会先使用http询问是否能够进行https请求如果浏览器只支持https会返回3XX状态码表示路径已经改变。然后浏览器才会使用新的https://开头的域名访问server但是这样每次都会多发一次请求而且还会造成中间人攻击hsts就是为了解决一个问题当访问过一次server之后server会返回 Strict-Transport-Security: max-age31536000; includeSubDomains这个响应行表示如果浏览器接收到使用 HTTP 加载资源的请求则必须尝试使用 HTTPS 请求替代。 如果 HTTPS 不可用则必须直接终止连接max-age是强制执行的时间这里是一年只要一年时间内浏览器再次访问这个域名就可以再次强制执行一年includeSubDomains表示当前域名及其子域名均开启HSTS保护而且对于tls握手过程中有问题的证书也会禁止访问hsts不仅提升了访问速度而且增强了安全性。 TLS1.3 TLS1.3相对于之前的版本有了更加安全和高效的密钥交换流程以下是截取tls1.3相比之前协议的改变接下来具体说一下tls的哪些改变详细的过程可以参考tls详解: ①1RTT的tls连接时间tls1.3还废除了rsa算法因为它不支持前向安全所以这里使用DHE算法作为讲解。 客户端发送client hello支持的加密套件该作用和之前一样、supproted_versions 拓展包含自己支持的TLS协议版本号、supproted_groups 拓展表示自己支持的椭圆曲线类型、key_share拓展包含客户端利用supprot_groups中各椭圆曲线算法生成的public keyserver 发送Server Hello携带如下几个重要信息supproted_versions 拓展包含自己从client的supproted_versions中选择的TLS协议版本号、key_share拓展包含自己选中的椭圆曲线以及自己计算出来的公钥接着发送Change Ciper Spec和Finished与tls1.2相同tls1.3相比1.2的DHE算法减少了一个RTT原因在于tls再client hello阶段就计算出了所有椭圆曲线算法的公钥供server选择。 ②0RTT的会话复用 与上图tls1.2的会话复用相同tls1.3的会话复用使用了相同的sessionid和ticket机制也是1RTT的时间。但是tls1.3的会话复用还可以实现0RTT的连接具体做法是 client hello中除发送上面的信息外还需要额外发送psk_key_exchange_modespsk的交换模式、pre_shared_key拓展将之前握手后发送的ticket处理之后形成的预共享密钥简称psk由于server可能会发送多次所以可能会出现多个,early_data拓展server是否支持0RTT的连接以及应用数据。server hello会有多种情况如果server验证ticket成功并且愿意0RTT连接那么sever hello会发送Encrypted Extensions里面携带了early data拓展表示自己会读取early data说明0RTT成功如果 server没有配置读取early data的选项但是ticket验证成功那么server就会忽略client发送的Application data这样只表示会话复用成功但不立刻接收数据需要1RTT如果ticket验证失败则回到了上面tls1.3 1RTT建立连接的过程。 3.HTTP/2 HTTP/2是对之前HTTP协议的扩展而非替代HTTP 方法、状态代码、URI 和标头字段等这些核心概念不变只是传输过程做了优化。http1为了实现请求的多并发只能创建多个连接和域名分片上下手但是六个浏览器都有自己的最大连接数这种策略不能从根本上解决问题而且创建多个连接也会增加握手消耗。 ①ALPN协议http2设计的时候为了考虑兼容性的问题需要客户端对服务器发起一次询问但是这样浪费一次RTT为了减少浪费客户端会在client hello时加上http询问请求这样做不仅减少了浪费还达到了h2强制使用tls的目的确保通信安全这种机制叫做ALPNApplication Layer Protocol Negotiation ②二进制分帧h2为了应对http1中的队头阻塞问题什么是http队头阻塞和tcp队头阻塞以及如何解决设计出了二进制分帧技术http1中的数据都是通过文本文本传输的但是二进制结构更有利于数据处理因为计算机只认识二进制所以传输时不需要文本与二进制之间的转换http1中的管道技术虽然支持反多次请求但是响应必须按照FIFO的顺序返回不能实现真正的并发所以存在队头阻塞问题。 针对这个问题h2将每个响应分成若干个帧序列而每个帧序列都有流号标记属于哪个响应这样即使每个帧序列乱序到客户端还是能够根据流id重新组装解决了http方面的队头阻塞真正实现多路复用。 例如下图客户端请求first函数和second函数响应便将每个函数分割成若干个帧序列然后填写流id和长度方便客户端组装。其中响应头会生成headers frame请求行会生成data frame除此之外还有其他种类的帧负责标记帧的用途 -----------------------------------------------
| Length (24) |
---------------------------------------------
| Type (8) | Flags (8) |
------------------------------------------------------------
|R| Stream Identifier (31) || Frame Payload (0...) ...
---------------------------------------------------------------Length 代表整个 frame 的长度用一个 24 位无符号整数表示头部的 9 字节不算在这个长度里。Type 定义 frame 的类型用 8 bits 表示。帧类型决定了帧主体的格式和语义如果 type 为 unknown 应该忽略或抛弃。Flags 是为帧类型相关而预留的布尔标识。标识对于不同的帧类型赋予了不同的语义。如果该标识对于某种帧类型没有定义语义则它必须被忽略且发送的时候应该赋值为 (0x0)R 是一个保留的比特位。这个比特的语义没有定义发送时它必须被设置为 (0x0), 接收时需要忽略Stream Identifier 用作流控制用 31 位无符号整数表示。客户端建立的 sid 必须为奇数服务端建立的 sid 必须为偶数值 (0x0) 保留给与整个连接相关联的帧 (连接控制消息)而不是单个流 -Frame Payload 是主体内容由帧类型决定。 帧类型主要有以下几种 HEADERS: 报头帧 (type0x1)用来打开一个流或者携带一个首部块片段DATA: 数据帧 (type0x0)装填主体信息可以用一个或多个 DATA 帧来返回一个请求的响应主体PRIORITY: 优先级帧 (type0x2)指定发送者建议的流优先级可以在任何流状态下发送 PRIORITY 帧包括空闲 (idle) 和关闭 (closed) 的流PUSH_PROMISE: 推送帧 (type0x5)服务端推送客户端可以返回一个 RST_STREAM 帧来选择拒绝推送的流RST_STREAM: 流终止帧 (type0x3)用来请求取消一个流或者表示发生了一个错误payload 带有一个 32 位无符号整数的错误码 (Error Codes)不能在处于空闲 (idle) 状态的流上发送 RST_STREAM 帧SETTINGS: 设置帧 (type0x4)设置此 连接 的参数作用于整个连接设置流量控制窗口的大小PING: PING 帧 (type0x6)判断一个空闲的连接是否仍然可用也可以测量最小往返时间 (RTT)GOAWAY: GOWAY 帧 (type0x7)用于发起关闭连接的请求或者警示严重错误。GOAWAY 会停止接收新流并且关闭连接前会处理完先前建立的流WINDOW_UPDATE: 窗口更新帧 (type0x8)用于执行流量控制功能可以作用在单独某个流上 (指定具体 Stream Identifier) 也可以作用整个连接 (Stream Identifier 为 0x0)只有 DATA 帧受流量控制影响。初始化流量窗口后发送多少负载流量窗口就减少多少如果流量窗口不足就无法发送WINDOW_UPDATE 帧可以增加流量窗口大小。 note:数据优先级: http2可以进行帧的多路复用但是某些文件可能需要尽快处理为此http2设计了数据帧优先级通过帧之间的依赖关系和权重值来分配资源带宽。例如上图示例Ⅰ可知帧AB处于同一级别但是权重不同所以帧A将分配到3/4的带宽而帧B只分配到1/4的带宽。 示例Ⅱ说明D是C的父级所以先分配D的带宽再分配C的带宽。 示例Ⅲ说明先D的带宽再分配C的带宽最后根据权重分配AB的带宽。 Note但是数据流依赖关系和权重只表示传输优先级而不是一种必要行为因此不能保证特定的处理或传输顺序。因为我们不希望在优先级较高的资源受到阻止时还阻止服务器处理优先级较低的资源。 ③头部压缩h2的另一个优势便是头部压缩在大多数时候我们请求或者响应的数据可能很少例如ajax请求但是同样需要传输各种请求头尤其是cookie。这无疑给http带来负担而头部压缩就是解决重复请求头发送的问题。为了方便所以直接使用链接中的图片 HTTP/2 头部压缩技术介绍 正如图中所示左边是请求头中间分为上下两部分上面是静态表将常见的请求头编码下面是动态表请求响应时动态添加的内容如cookies两个表使用连续的空间所以画在了一起右边是根据头部压缩得到的编码。头部压缩每个字节都表示不同的含义根据字节前面的标识就可以分辨是哪种请求头。下面讲解一下头部压缩的编解码大致原理 请求头在静态索引表或者动态表中的如methodget或者path/或者动态表添加的内容等可以直接使用索引表示。索引表中的内容以1开始剩下的七位表示索引表中的条目这样只用1个字节就可以表示原来很多字节的内容。 0 1 2 3 4 5 6 7
------------------------
| 1 | Index (7) |
------------------------------请求头不在字典表中但是需要添加到动态表中的使用“01”开头后面如果是“000000”说明请求头参数名不在字典中否则可以根据索引值在静态或者动态表中找到条目。接着后跟的字节标识请求头参数值H为1表示使用哈夫曼编码否则表示使用字符串编码。如下图选中的字节“0110000”表示不在表中但是请求头参数名在字典中为32表示cookie剩下的字节“10011100”表示参数值使用哈夫曼编码长度是28而开头字母u的哈夫曼编码表示为“101101”正好与接下来的序列相符这里我们看出头部压缩的好处。 字符串的哈夫曼编码可能不是以整八位比特位结束的这就需要在哈夫曼编码的最后添加“EOS填充1”结束标记。哈夫曼编码是根据各字符经常使用频率而创造的序列可以减少编码量如字符a需要使用1个字节但哈夫曼编码“00011”即可表示它,一般我们也会看到十六进制表示的请求头这是由二进制编码转换而来的。哈夫曼编码表 //请求头的参数名在字典中但是参数值不在表中0 1 2 3 4 5 6 7
------------------------
| 0 | 1 | Index (6) |
-----------------------------
| H | Value Length (7) |
------------------------------
| Value String (Length octets) |
-------------------------------
//请求头的参数名和参数值都不在表中0 1 2 3 4 5 6 7
------------------------
| 0 | 1 | 0 |
-----------------------------
| H | Name Length (7) |
------------------------------
| Name String (Length octets) |
------------------------------
| H | Value Length (7) |
------------------------------
| Value String (Length octets) |
-------------------------------请求头不在字典中但是不添加到动态表中使用“0001”开头大致过程与第二种情况相同。 //请求头的参数名在字典中但是参数值不在表中0 1 2 3 4 5 6 7
------------------------
| 0 | 0 | 0 | 1 | Index (4) |
-----------------------------
| H | Value Length (7) |
------------------------------
| Value String (Length octets) |
-------------------------------
///请求头的参数名和参数值都不在表中
0 1 2 3 4 5 6 7
------------------------
| 0 | 0 | 0 | 1 | 0 |
-----------------------------
| H | Name Length (7) |
------------------------------
| Name String (Length octets) |
------------------------------
| H | Value Length (7) |
------------------------------
| Value String (Length octets) |
-------------------------------但是需要说明的是如果请求头参数名在字典中的索引很大比如1234怎么办我们这种结构只能存储最大值为15的索引这就需要用到前缀编码以第三种情况众多的四位前缀编码为例存储x 1234过程这个过程与十进制转换二进制的过程有些相似 首先将最大值1111填入后四位那么x x-15 1219接着需要将剩余的部分填入接下来的字节中计算x x%12867为什么使用128而不是256因为需要一位标识这个数据是否结束因为数据可能需要填入多个字节中为0则表示数据结束。需要将67填到下个字节的剩下七位中。接着计算x x/1289;x 9128数据计算结束将下个字节的首位置零标识这个数据一表示完成剩下7位填入9得到的序列就是 0001 11111100 00110000 1001。解码时可以将后两个字节去除首部颠倒顺序排列再加上1111就可以得到1234。 计算代码如下。 //编码过程
if I 2^N - 1, encode I on N bits
elseencode (2^N - 1) on N bitsI I - (2^N - 1)while I 128encode (I % 128 128) on 8 bitsI I / 128encode I on 8 bits
//解码过程
decode I from the next N bits
if I 2^N - 1, return I
elseM 0repeatB next octetI I (B 127) * 2^MM M 7while B 128 128return I-还有一种请求头不在表中但是绝对不添加索引的首部这种和第三种情况相同唯一不同的是这种情况会作用于网络中的每一跳每一个路由设备如果中间通过代理代理必须原样转发不能另行编码。而上一种首部只是作用当前跳通过代理后可能会被重新编码 ④Server Push 在http1中上一个响应发送完了服务器才能发送下一个请求但在http2里可以将多个响应一起发送。例如在一个html文件中有个多jscss文件为了快速解析页面可以直接向客户端推送js文件从而减少客户端请求的时间。 http2多路复用的好处 连接少握手成本就少。压缩比高因为一个连接上积累的信息很多压缩比会更高。更好地利用 TCP 的特性为什么因为 TCP 的拥塞控制流量控制都是基于单个连接的如果使用很多个连接特别是在网络拥塞的情况下会放大拥塞的系数加剧网络拥塞如果使用一个连接当得知该窗口已经拥塞响应很慢便不会继续发送了但是多个连接的情况可能大家都会尝试发一下而导致加剧网络拥塞。使用更少的域名这也是为了更好地使用连接并且减少了 DNS 解析时间。 http2存在的缺陷http2虽然实现了多路复用但是并没有解决tcp方面的队头阻塞。而且同一个连接内多个流传输可能会导致RTT时间变长相比http1容易出现超时重传再者h2适合于大量冗余的请求对于少量请求并没有太大优势。 4.HTTP3 前面提过http2虽然解决了http方面的队头阻塞但是并没有解决传输层的队头阻塞tcp层那么tcp层的队头阻塞是什么意思 tcp是可靠的传输层协议所以我们的http以及ftp都是用tcp作为传输层协议但是也是因为tcp的可靠传输造就了tcp的队头阻塞问题因为tcp为了保证数据准确且有序的发送到接收端使用了滑动窗口协议。 滑动窗口协议发送端会为发送的数据标上序列号便于接收端组装处理接收端接收只有接收到按需到达的数据后才能交给应用层如果有发送报文丢失那么未按序列到达的报文只能等待之前序列号的报文到达才行。例如发送依次发送1,2,3,4,5,6六段报文到达顺序为1,2,4,3,65报文丢失那么12报文按序到达可以直接交给应用层处理4报文需要等到3报文到达后才能交给应用层6报文属于未按序列到达此时只能等到5报文超时重传才能向上传递。所以即使http2使用流分帧技术但是tcp层还是需要一个个的按序传输才行。除此之外为了提高了网络传输的性能人们开始研究新型的http协议。如果还从tcp协议入手不仅不能解决http2的队头阻塞还有一些其他的问题中间设备的僵化一些路由器、网关或者防火墙默认tcp协议的端口和选项导致tcp无法出现使用新的格式。操作系统的僵化tcp协议栈是属于内核的一部分我们只能使用了socket接口。一旦修改tcp可以需要修改操作系统的代码。握手时间长tcp建立连接总是需要三次握手四次挥手这样无形中增加了浪费。 udp可以很好的避开上面的所有问题所以新的http3协议使用udp为传输层协议但是udp是不可靠的传输层协议所以就需要自己实现tcp的流量控制和拥塞控制。 4.1http3还是比http2的优点
更快的连接时延 http1一次tcp握手两次tls握手至少需要三次握手才能发送数据TLS1.3可以实现两次握手就发送数据到后来的TFOTLS1.3的session reuse才能真正实现0RTT的握手连接但是这需要通信双发都支持TFOTLS1.3而且是session复用的情况下。 而udp不需要握手就可以直接发送数据再加上支持tls1.3所以可以实现1RTT或者0RTT的连接。 没有tcp的队头阻塞 没有使用tcp自然也不会有tcp的队头阻塞但是如何保证数据有序到达呢 http3使用http2中流的思想在应用层和传输层加了个quic协议层将从http3应用层收到的数据封装成quic帧每帧都有流id和字节长度。这样接收到数据后就可以根据流id和字节长度重新拼接数据。同样的一个连接可以建立多个流而每个流可都以不影响的发送各自的帧因为udp不需要整个字节序列按序达到就可以交给quic层而quic则可以根据流id组装数据。 加密的报文头部 tcp使用tls虽然能加密报文数据但是tcp首部没有加密。所以在传输过程中很容易被中间网络设备篡改注入和窃听。比如修改序列号、滑动窗口。quic 的 packet 可以说是武装到了牙齿。除了个别报文外所有报文头部都是经过认证的报文 Body 都是经过加密的。 连接迁移 什么叫连接迁移就是当网络环境发生变化时这条连接不中断。一般我们使用手机上网时可能会因为移动或者切换网络而导致IP地址变化这样我们又需要与原来的服务器进行重新连接。而我们的请求可能也需要重发。又比如我们使用一个公共ip上网时可能会因为竞争需要重新进行端口映射。这是因为传统网络使用四元组源ip目的ip源端口目的端口来辨别连接http3不使用四元组而是用conntion id来标识连接。即使ip或者端口发生变化连接也不会中断上层逻辑不感知变化。 4.2拥塞控制 [QUIC-流量控制] 拥塞控制是为了防止过多的数据进入网络导致网络阻塞网络数据丢失率高例如中间设备未能及时的接收数据包而丢弃 http3的udp并没有完成拥塞控制算法这就需要我们自己实现与拥塞控制相同的功能。虽然工作量多了但是现在设计的拥塞控制功能可以使用最新的算法弥补或者避免过去tcp的缺陷。 ①可插拔的算法设计 我们可以在用户层实现自己的拥塞控制算法可以很方便的升级和修改配置不需要改变内核部分。不同应用程序的不同连接可以配置不同的拥塞控制算法更精准有效。 ②避免RTT计算的歧义 RTT是一次数据在客户端接收端往返的时间它会根据上次数据的往返时间从发送数据开始到接收到数据的Ack为止不断更新。但是如果发生重传原来数据的Ack与重传数据Ack的序列号相同这就会在计算RTT的时候就会发生歧义。无论以哪个计算都不能确定RTT一定是准确的。为了解决这个问题http3在每个quic帧上都添加了自增的Packet Number这样就可以区分到底是哪个数据的ack了。但是单纯依靠严格递增的 Packet Number 肯定是无法保证数据的顺序性和可靠性。QUIC 又引入了一个 Stream Offset 的概念。quic帧可以依靠 Stream 的 Offset 来保证应用数据的顺序即使发生重传帧也可以根据offset进行排序。 ④更多的sack块 如果帧没有按序到达为了减少重传的帧序列会在tcp帧的首部增加已经到达的帧的范围例如12345如果1245到达3缺失在发送ack帧时就可以选择发送2的确认ack以及4至5的sack。这就告诉发送端帧2收到可以从帧3发送但是帧45已经收到不需要再发送了。原来的tcp首部由于长度的限制最多填写3个帧范围。而现在的quic首部可以填写更多sack帧范围。 ⑤不允许Reneging 什么叫 Reneging 呢就是接收方已经接收并且上报给 SACK 选项的内容 但是接收方因为服务器资源有限比如 Buffer 溢出内存不够等情况而丢弃数据这种方式在http3中不被允许可以减少干扰。 4.3流量控制 QUIC-流量控制 流量控制用于解决发送端和接收端速度不匹配的情况如果发送端发送太快会导致接收端无法接收而丢弃数据包数据接收率低如果接收端太快而发送端比较慢也会使得网络传输率低。流量控制就是为了平衡接收端和发送端的速度问题或者特定数据流的传输请求等例如视频倍速播放等。 http3流控中接收端发送WINDOW_UPDATE帧通知对端接收窗口的大小增长比如说能接收更多的数据发送端也可以发送BLOCKED帧表明数据发送受制于接收端的窗口无法发送数据。 流量控制的大致过程图中flow control receive offset表示最大的接收窗口也可以看成初始时服务器端允许客户端发送的最大窗口绿色部分表示接收端读取的数据黄色部分表示到达但还没有接受的数据空白间隙表示没有按序到达的块flow control receive window表示接收窗口当接收端读取的数据绿色部分大于最大接收窗口flow control receive offset的一半时会增加最大接收窗口读取多少扩大多少同时发送WINDOW_UPDATE帧通知客户端发送窗口。如果接收窗口flow control receive window小于0则发送BLOCKED帧通知发送端停止发送。quic的流量控制与tcp的不同在于TCP 为了保证可靠性窗口左边沿向右滑动时的长度取决于已经确认的字节数。如果中间出现丢包就算接收到了更大序号的 Segment窗口也无法超过这个序列号而QUIC 不同它的滑动只取决于接收到的最大偏移字节数图中黄色最右边的位置即使中间有包未收到也跟接收窗口没有关系。 此外http3和http2一样同时提供流级和链接级别的流量控制。还有流和连接两种流量控制连接的流量控制是针对连接内所有流的。 参考哈夫曼编码的理解 https过程解析 浅谈SSL/TLS工作原理 - 知乎 (zhihu.com) ALPN协议 HTTP/2协议 使用 Wireshark 抓取 HTTP1/2 流量 TLS 1.3 协议详解 TCP选项之SACK选项概述 TCP 的那些事 | D-SACK TCP中的RST标志(Reset)详解 TCP的快速重传机制与累计确认机制 HTTP协议学习笔记–http1.0、http1.1、http2.0、https、http3 面试官一个TCP连接可以发多少个HTTP请求 - 知乎 (zhihu.com) 图解 ECDHE 密钥交换算法 - 爱码网 (likecs.com) 几幅图拿下 HTTPS (qq.com) 关于队头阻塞Head-of-Line blocking看这一篇就足够了 HPACK 介绍 (gohalo.me) HTTP2 详解 - 简书 (jianshu.com) QUIC详解-网络编程/专项技术区 HTTP 协议概述 - 博客园 (cnblogs.com)