HTTP的前世今生

news2024/11/16 1:58:32

承接上文HTTP请求的详细过程

http协议版本历史

http造就了万维网,http成就了互联网第三次信息技术革命并且影响着即将到来的第四次人工智能技术革命。

1989年第一个http协议,http0.9发布,发明了万维网,创建了世界第一个网页浏览器;

http1.0版本是在1996年正式发版的 ,这个时候才丰富了交互响应的文件类型,96年之前网页是不能播放音乐的;

97年发布http1.1版本,2015年才发布http2.0版本,源自谷歌的SPDY协议,目前现代浏览器完全支持http2.0,http2可以更好的表达设备的在线状态;

2022年6月,发布了http3 ,使用QUIC协议替代了TCP协议,作为位于应用层的通用传输协议,这是一种基于UDP构建的多路复用传输协议;

http3.0版本解决了TCP的一些问题,提高效率并保留了TCP的所有优点。

http2和http3这2个协议版本都是由谷歌主导的,并且第一个在chrome浏览器率先实现的;

http0.9到1.0版本见证了web1.0时代的开始,http1.1-2.0版本见证了web1.0并完成了它的使命和见证了web2.0时代发展到了今天。

这是开放式系统互联的OSI七层模型图,http协议位于应用程序层,需要经过传输层才能进行通信。

理论上传输层用哪个协议并不是那么重要,但一定要知道传输层的TCP和UDP两个协议到底是什么,着重介绍传输层的原因是因为它对http协议至关重要,后面的IP层和其他底层对TCP和UDP都很友好,而且对http各个版本的发展并没有影响。

TCP协议即传输控制协议,首先通过三次握手建立连接,然后传输数据,数据传输完毕,进入四次挥手关闭连接,这中间出现了数据丢失,则会重试保证数据传输可靠性。

可以看出TCP是一个面向连接的可靠的传输协议,而UDP协议是用户数据协议,是面向数据报文的,发出去就发出去了,发不出去就发不出去,发丢了消息也不会去重试,UDP不需要握手建立连接,发送消息的数据又小,所以速度更快。

为了保证传输的可靠性,http0.9到2.0版本都是采用tcp协议传输,到了3.0版本就抛弃了tcp改用udp传输,利用QUIC协议在应用层保证数据传输的可靠性;

http0.9是万维网第一个http协议,经过三次握手建立连接,客户端发起get请求,服务器仅能响应http文本类型的数据,但不能在客户端显示图片和播放音乐,客户端收到数据之后,四次挥手关闭连接,所以也叫单线协议,同时http0.9版本没有http标头,没有状态码、错误码,

如图所示仅仅使用一行请求信息,所以也叫它单行版本,就是因为0.9版本太简陋,服务器仅能响应html文件,比如制作个人网页,

于是就有了http1.0,请求加入了http协议标头,响应加了状态码和传输的内容类型,

也就是经常在服务器配置的MIME媒体类型,即多用途互联网邮件类型。

不为http服务器配置MIME类型,服务器就没办法解释这个内容类型是个啥,客户端也不认识就会出现问题,服务器配置好以后,就可以传输更多类型的文件内容数据了。

和0.9版本一样,1.0版本还是单线协议,一个连接只能处理一个请求一个响应,每次建立物理连接的成本很高,

并且服务器遭受不住太多客户端访问,否则服务器扛不住就会直接给你报503错误,为了减轻服务器压力,出现了升级的http1.1版本,该版本中引入了一个重要的概念,就是持久连接的概念,

即增加了keep-alive值的标头,就意味着建立连接后,指定时间内不会关闭这个连接,可以在保持的这个连接上发送多个请求,并且不会出现一个往返就关闭连接的情况,

节省了每次交互都会握手和挥手的时间,除此之外1.1版本还引入了流水线概念,在服务器响应前,客户端可以一次发送多个请求,服务器收到多个请求后,按顺序将准备好的数据再一个一个的回复给客户端,对比一下左边一次一个请求一个响应和右边一次多个请求逐个响应的过程,可以看到明显的节约了请求发送的时间,提高了传输的效率。

按顺序响应有没有问题?

  • 线头阻塞问题

首先就会造成一个重要的问题,head of line blocking(线头阻塞即流水线头阻塞),

假如客户端处理了三个请求,第一个请求处理的时间太长,第二个第三个请求是不是得必须老实的排队,等待第一个请求处理完成呢?

这就造成了流水线的塞车现象,在这个版本中解决塞车的办法就是浏览器通常会保持6个左右的连接以缓解一个连接塞车,客户端可以通过其他连接继续发送请求。

  • http标头冗余问题

在连续发送请求的情况下,每次请求总是会带上相同基本不会变化的http标头,并且http1.1发送的数据还是纯文本的,传输数据不但大还啰嗦。

http2协议

以上2个问题就是http2要解决的,http2协议是http1.1版本的扩展而不是替换,因为它只是更好的解决了1.1版本的问题和功能补充,

b站网络请求就是使用的http2协议,

http2在应用层改变了传输方式,之前版本应用程序层传递的http标头和数据都是明文的,

http2在应用层增加了一个二进制帧数据处理层,

将http标头和数据明文消息拆分成二进制数据帧进行传输,

每个数据帧包含自己携带的数据并用stream id做标识,这也解释了什么叫数据流,就是将数据切开形成数据帧,然后将它们单独或者打包成独立流传输到目的地后,

再按照stream id将它们组装起来还原成原始数据。

好处就是OSI模型应用程序下的底层协议,更喜欢二进制数据帧,因为它们的大部分工作被应用程序层做了,它们的活少了,响应的网络传输速度也就提高了。

另一个好处就是再大的文件也给你剁的细碎,规避了大文件传输大小的限制,比如IIS、apache等http服务器都有对单个请求体又大小的限制。

客户端以流的方式请求,服务器以流的形式响应,就形成了双向数据流,数据帧都用stream id做标识,然后stream id将多个数据帧识别为一个消息,

保证了数据的完整性。

http2协议是客户端与服务器建立一个连接,再加上双向数据流,客户端和服务器的交互就可以重用它们建立的单个连接传递数据,就形成了http2的多路复用。

既然数据帧标明了stream id,那么传输数据流的顺序可以是乱序的,当然传输数据也可以设置优先权重的,

无论是客户端还是服器接收到的流数据先到的在缓冲区先组装,不用等待前一个请求数据处理完成再处理下一个,

就这解决了http1.1应用程序层的http线头阻塞的问题,http2是否真正解决了线头阻塞的问题?

之所以前面着重强调的是应用程序层的http线头阻塞,原因是http2仅在二进制帧处理层拿到完成的tcp数据后解决了线头阻塞问题,http2同样基于传输层的tcp协议传输的,

TCP标头格式

tcp协议为了保证消息可靠,顺序传递消息,就有可能造成塞车的情况,所以传输层的tcp线头阻塞问题并没有得到解决,为了说明这个问题,来模拟下传输层tcp传递数据包的视角。

当打开b站,我们和浏览器都明白我们向b站服务器请求获取js、css等文件资源,

http2通过前面讲的二进制帧数据处理层,将数据剁碎,加入stream id,用数据流的方式传递数据,其他的,http2并不关心,更不用说到达传输层的tcp协议了,甚至都不知道这是传输的是http请求、响应的信息,tcp只知道数据包的最大大小通常是1450字节。

http2跟踪传输的指定字节范围的数据部分,以便可以按正确顺序来还原原始数据,

假如tcp数据包2在传输过程中丢失了,

那么tcp数据包1和3会提前达到缓冲区,tcp就会发现数据包1和3之间缺少了数据包2的字节范围数据,哪怕http2知道tcp数据包1中有stream id为1的数据帧,加上tcp数据包3中stream为1的数据帧,可以组装成一个完整的消息,也要耐心等待tcp至少重返服务器一次,来重传丢包的数据2的数据副本到达才能继续解包其他tcp数据交给应用程序层,就是丢失的tcp数据包2阻塞了tcp数据包3导致了tcp的线头阻塞,所以结论就是http2并没有完全解决线头阻塞的问题。

接下来讲个http2重要的扩展功能:

http2服务器推送功能

首先正是因为http2具有双向流、多路复用的特点 ,才更有利于http2提供的服务器推送功能,比如直接打开b站 请求的是首页,

b站服务器可以将未经过请求的、首页所需的js、css等文件资源准备好之后直接推送给我们;

同时对于前端开发者,http2更加有益于html5套件的SSE功能(Server-Send Events即服务器发送事件),

服务器推送功能进一步减少了网络请求的数量,提高了交互的效率。

http2标头压缩功能

打开浏览器开发者工具,直接进入百度首页,

百度依然使用的是http1.1版本,

百度首页的请求标头是689字节,响应标头是598字节,点击标头标签可以看到请求和响应的所有标头信息,尝试刷新下页面,看到请求发送标头大小没有任何变化,说明http1.1来回总是在说车轱辘话。

b站使用的是http2协议,

b站首次请求的标头大小是387字节,响应的标头大小是417字节,进入标头标签可以详细看到http2请求和响应标头信息,

再次刷新页面,发现请求标头缩小至116kb,响应字节也小了,

再次刷新页面,发现b站请求和响应标头更小了,而达到这种节约网络请求的标头大小的效果就要归功于http2是使用HPACK来编解码http标头的。

HPACK的原理就是建立连接的客户端和服务器都维护着相同的61个条目的只读的静态表和可动态添加条目的空白的动态表,

当请求发送的时候先查找表中的名值,名值完全匹配直接提取该标头在表中对应的整数索引用于表示该名值对。

如果只匹配名称,则使用索引表示名称,值就用霍夫曼huffman算法进行编码后表示,

表中没有的,则按照顺序添加到动态表中,再使用霍夫曼算法编码名值对字符后传递给服务器;服务器端则反之, 使用表中的索引解码或者按顺序使用霍夫曼算法进行解码后添加到服务器动态表中,这样保证双方的表中保存的数据和整数索引是一致的,在之后的所有请求的标头会越来越小,减少了网络数据流量来提高交互的效率。

这是http2标准中已经定义的61个标头的静态表,

类似:path这样的标头名称,被称为伪标头,出现伪标头的原因是为了兼容之前的版本,

http2的标头都是名值对,之前版本的标头都存在标头行,http2将http1的标头行拆分成名值后的名称前加上了冒号,方便与http2的标头名称进行区分。

什么是霍夫曼算法

最优前缀码算法,利用二叉树将出现频率大的符号采用较短的有效编码,频率小的有效编码更长,解决等长编码解压时出现歧义的问题,

字节下的数字代表这个字母出现的频率,

霍夫曼算法会先从出现频率低的两个字母,按照左树代表0放出现频率小的字母

右树代表1放出现频率大的字母的原则合并组成一个新节点。

以此类推最终组成一个二叉树,

以上6个字母的最终编码如图所示,a=0直到f=1100,你是否认为http2每次都对未出现在表中的标头字符都这样算一遍?

http2标准按照标头字符的使用频率,专门准备了一张霍夫曼编码表,刚好256个条目,

对应ASCII编码表示的256个可能的字符,那么对应霍夫曼编码表,编码就不需要二叉树运算了,提高了编码的效率,例如在霍夫曼编码表中,位于索引47位置的符号/,由6位二进制编码011000组成,16进制编码值就是0x18。

http2留给我们的三个思考

  • 了解HPACK原理之后 是不是可以更好的优化网络请求?

因为客户端对同一个网站交互越多,

动态表中积累的http标头条目就越多,标头压缩的效果就越好,所以这里有一个http2的优化技巧,交互最好是同域名或者同域名下不同二级域名指向的服务器ip是一样的,

而且使用的是同一个加密证书,这样会确保使用相同的静动态标头表,这也解释了为啥泛域名的SSL加密证书每年费用那么贵的原因。

HPACK是按顺序编解码标头的是不是也会造成线头阻塞问题?

是的,因为http2数据流可以是无序的,

请求数据流达到服务器后,请求携带编码后的标头中,

发现有个请求标头索引比服务器解码动态标头表中的最大索引值还大,就会造成无法解码,而导致使用该请求标头相关的数据流都会被阻塞,直到携带该索引表示的正确霍夫曼编码的数据流达到后,

才能解码之前的请求数据流,如果这条数据流丢包了,就会造成塞车时间更长,目前这个塞车问题只能留给http3解决了。

第三个思考是使用多路复用,它真的就比之前版本的按顺序传输更快吗

真正解决了交互事务中的线头阻塞问题了吗? 答案是不一定

不是说好了速度更快且没有http线头阻塞问题?

首先表象的看http2和现代浏览器强制了必须使用https加密超文本协议传输,那https是如何工作的?

相比于http1.1之前不强制使用https加密,http2在加密交换密钥的过程中,最少增加了2个往返时间即2RRT(Round-Trip Time),反而减慢了交互速度。

另一个是多路复用中数据被切碎成数据帧,并用stream id标识打包成数据流传输,这样就可以乱序传输了。

假如我们一次请求一个js或css文件,根据文件大小假如被切分成了5份和3分,来对比下顺序传输和乱序传输

,顺序传输的js文件的接收速度比乱序的js传输速度更快,

总的到达时间基本一致的,所以在http2中的多路复用,就需要根据实际情况考虑使用优先级控制优化了。

再比如乱序中某个数据的丢包,在缓存中排序组装消息的时候发现少了一帧,

就需要至少往返一次服务器,拿丢失的数据帧副本,虽然没阻塞其他的消息,但确实阻塞了自己,所以这个问题 不单单存在于http2,http3的多路复用也存在这个问题,虽然这种数据流的线头阻塞是概率问题,但确实存在。

http3

它是基于QUIC协议的升级版本,

已经知道了http2基于传输层的tcp协议传输,仅仅解决了在应用程序层的http线头阻塞的问题,

但又由于传输层的协议基本由系统实现,应用程序层无法干涉,所以http3就想,既然动不了你,干嘛不直接抛弃你,http3就直接使用了传输效率更高的UDP,虽然UDP不保证消息传输的可靠性,但在http2已经解决了应用程序层http的线头阻塞问题的基础之上,

http3在应用程序层适配UDP并保证数据传输的可靠性,就推出了基于UDP的QUIC协议,可以说它是tcp2.0,只不过是在应用程序层实现的,QUIC协议实现了tcp的可靠性、拥塞控制、流量控制、排序等功能和保留了http2基于流的多路复用及http2优化的其他功能。

http3将基于UDP的流作为一等公民和http2的流处理有2个重要区别

一个区别是http3使用动态标头编码QPACK和http2使用HPACK,QPACK和HPACK在编解码方式都是一样的,重要区别在与QPACK增加了静态表中的标头条目至98个。

另一个就是解决HPACK按顺序解码容易造成线头阻塞的问题,

QPACK的解决办法就是使用指令独立流,

提前讲好需要增加的标头项,使用添加指令发送给解码方,解码方收到后回复确认标头指令,从而双方利用标头动态表中标头项的状态,来确认标头是否完成同步,标头项状态未被确认的,请求的数据流就不会使用该项标头的索引编码标头以解决动态标头解码的塞车问题。

另一个区别就是因为QUIC协议实现了tcp协议的所有功能,那QUIC协议如何规避tcp线头阻塞的缺点?

http2存在tcp的线头阻塞,是因为tcp只知道跟踪携带的字节范围数据,并不知道我们前面讲的tcp线头阻塞例子中数据包1中的stream id为1的数据帧和数据包3中的stream id为1的数据帧可以组装成一个消息,因为tcp根本不知道传输的具体细节。

在http3中QUIC协议优化了帧的组成部分,脱掉了tcp外衣,直接在数据帧中加入了Offset字节范围帧头,

这样就能根据stream id和Offset帧头,判断哪些数据包中的帧数是同一个消息,因此例子中数据包1中的stream id为1的数据帧,

就可以和数据包3中的steram id为1的数据帧组成一个消息,因为它们的字节范围可以匹配的上,这样就解决了即使丢了数据包2,也不影响其他消息的情况,从而消除了tcp线头阻塞的缺点。

http3的三个重要优点

基于UDP有个明显的好处就是数据到达传输层是需要加入传输层协议的头部。

http2和之前的版本使用的是tcp协议,

需要20-60个字节的头部,

而http3采用传输层的UDP协议,头部仅仅8个字节,这样就进一步优化了交互数据的大小,提高了传输速度,QUIC协议基于UDP有个更大的好处就是0往返时间建立连接即0 RTT,

tcp建立连接是需要经历3次握手和四次挥手的,QUIC协议是基于UDP的,就不需要三次握手和四次挥手,名义上实现了0 RTT,但是http3也需要加密传输,直接将加密协商信息和请求数据一起发送给服务器,只需要1个RTT就可以完成建立连接,相比于http2的加密协商至少需要2个RTT来说,还少了一个RTT。

第三个优点:tcp是基于连接的,而QUIC协议基于UDP的数据传输,是基于报文的,那http3怎么识别当前连接并实现多路复用的?

使用tcp建立的连接会基于源IP、源端口、目的IP和目的端口四元组信息,来确认是否已经建立过该连接,假如说从wifi切换到5G至少会导致四元组信息中的源IP地址信息会发生改变,tcp就必须重新建立连接,

而QUIC协议使用的是随机数作为connection id即连接id,来识别客户端和同域名服务器建立连接,从而不受网络变化的影响,通过connection id确定了连接,当然就可以实现和http2一样的双向流多路复用的功能,基于这个优点,http3协议就非常适合移动互联网了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/381540.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

软件测试面试必杀篇:【2023软件测试面试八股文宝典】

800道软件测试面试真题,高清打印版打包带走,横扫软件测试面试高频问题,涵盖测试理论、Linux、MySQL、Web测试、接口测试、App测试、Python、Selenium、性能测试、LordRunner、计算机网络、数据结构与算法、逻辑思维、人力资源等模块面试题&am…

Jinja2----------过滤器的使用、控制语句

目录 1.过滤器的使用 1.过滤器和测试器 2.过滤器 templates/filter.html app.py 效果 3.自定义过滤器 app.py templates/filter.html 效果 2.控制语句 1.if app.py templates/control.html 2.for app.py templates/control.htm 1.过滤器的使用 1.过滤器和测…

在linux中配置环境变量

1. 环境变量的作用 环境变量是操作系统在运行的时候,记录的一些关键性信息,用于辅助系统的运行。 在linux中执行 evn 命令即可查看当前系统中记录的环境变量。 环境变量是一种KeyValue结构 2. 符号$ 在linux系统中,$,用于取“…

【C++】STL——list的模拟实现

list的模拟实现 文章目录list的模拟实现一、list三个基本类的模拟实现总览二、节点类接口实现模拟实现构造函数三、迭代器类接口实现1.正向迭代器默认成员函数构造函数六种运算符重载 */->//--/!/2.反向迭代器四、list类接口实现1.默认成员函数1.1.构造函数1.2.析构函数1.3.…

Hive3.1.3安装部署_最小化部署_元数据MySQL部署_Hiveserver2部署_metastore部署---大数据之Hive工作笔记0012

hbase 实时分析 hive 离线分析 这里是新版本的hive3.1.3的安装 关于hive的原理之前的博客已经详细说了 可以看到上面是hive运行的原理图 词法分析 语法分析

P6软件如何设置权重体系

卷首语 同时,由于项目包含不同专业、不同类型的活动,需通过建立科学的测量体系以将底层活动的进度逐层汇总从而获得项目总体进度数据。 权重体系的确定 进度检测权重体系的建立过程,即是确定进度检测层级中的每项元素对其上一级元素进度的…

Github每日精选(第102期): PyGWalker将panda数据帧转换为Tableau风格的用户界面,用于可视化分析

PyGWalker可以简化Jupyter笔记本的数据分析和数据可视化工作流程,方法是将panda数据帧转换为Tableau风格的用户界面进行可视化探索。 PyGWalker(发音像“Pig Walker”,只是为了好玩)被命名为“Graphic Walker的Python绑定”的缩写…

ChIP-seq 分析:Peak 注释与可视化(9)

1. 基因注释 到目前为止,我们一直在处理对应于转录因子结合的 ChIPseq 峰。顾名思义,转录因子可以影响其靶基因的表达。 转录因子的目标很难单独从 ChIPseq 数据中确定,因此我们通常会通过一组简单的规则来注释基因的峰: 如果峰与…

二月安全月报 | 45亿条快递数据疑泄露,Twitter史上最大规模宕机

为了让大家更全面的了解网络安全的风险,顶象针对每月值得关注的安全技术和事件进行盘点总结。 国内安全热点 👉业务安全 男子注册上万账号薅羊毛获利13万 近日,上海市,由闵行区人民检察院提起公诉的刘某某诈骗一案开庭审理&…

Stream流和不可变集合

一、不可变集合 什么是不可变集合? 不可变集合,就是不可被修改的集合。 集合的数据项在创建的时候提供,并且在整个生命周期中都不可改变。否则报错。 为什么要创建不可变集合? 如果某个数据不能被修改,把它防御性地拷…

Apache Airflow Hive Provider 任意Hive命令执行漏洞

漏洞描述 Apache Airflow 是一个以编程方式管理 workflow 的平台,Airflow Hive Provider 是一个使用 SQL 进行读取、写入和管理分布式存储中的大型数据集的工具包,_prepare_cli_cmd 方法用于创建 Hive 连接命令列表。 由于 Airflow Hive Provider 5.1.…

论文阅读:MPViT : Multi-Path Vision Transformer for Dense Prediction

中文标题:基于多路视觉Transformer的密集预测 提出问题 创新点 提出了一种具有多路径结构的多尺度嵌入方法,以同时表示密集预测任务的精细和粗糙特征。全局到局部的特征交互(GLI),以同时利用卷积的局部连通性和转换器…

汽车刹车传感

一、方案概述:刹车传感器,作用于刹车系统的传感器类型,帮助驾驶人员判断刹车片的磨损情况,便于及时检修维护,保证制度系正常稳定工作。刹车片报警基本有两种,第一种是比较简单的机械报警,就是当…

Android Framework-Android进程/线程和程序内存优化

Android进程和线程 进程(Process)是程序的一个运行实例,以区别于“程序”这一静态的概念;而线程(Thread)则是CPU调度的基本单位。 Android中的程序和进程具体是什么概念呢? 一个应用程序的主入…

十一、Vben框架部分组件样式的重新封装

在使用vben框架的时候发现部分的样式不符合实际的需求,ant-design-vue的样式也不支持我们的需求,那怎么办呢,只能自己来修改,下面我就改大家说说我遇到的一些修改过的样式和组件。 一、inputNumber带前后标志 先看下目前支持的样…

命令查看Linux服务器内存、CPU、显卡、硬盘使用情况

命令查看Linux服务器内存、CPU、显卡、硬盘使用情况 查看内存使用情况 使用命令:free -m 大致结果类似下图: 内存占用情况 参数解释: Mem行(单位均为M): total:内存总数used:已…

4.4 like通配符关键字过滤查询数据

文章目录1.概述2.LIKE关键字3.百分号(%)通配符3.1 单个百分号(%)通配符3.2 多个百分号(%)通配符3.3 在值的中间使用百分号(%)通配符3.4 注意事项4.下划线(_)通…

centos7 配置samba

samba概述: Windows与Linux之间通信的桥梁,Samba是一个非常强大的文件服务器。Samba端口:udp 137 udp138,tcp139 tcp445。Samba工作模式:C/S模式(客户端-服务器) samba应用环境 1、文件共享&…

python库--urllib

目录 一.urllib导入 二.urllib爬取网页 三.Headers属性 1.使用build_opener()修改报头 2.使用add_header()添加报头 四.超时设置 五.get和post请求 1.get请求 2.post请求 urllib库和request库作用差不多,但比较起来request库更加容易上手,但该了…

SpringCloud学习笔记 - 分布式系统全局事务管理 - Seata1.5.2+Nacos+OpenFeign

1. Seata 是什么? 由于业务和技术的发展,单体应用被拆分成微服务应用,原来的三个模块被拆分成三个独立的应用,分别使用三个独立的数据源,业务操作需要调用三个服务来完成。此时每个服务内部的数据一致性由本地事务来保证, 但是全…