【业务学习】2019-05-09 http1.1&2.0的基本原理

Grape
所有视频:https://segmentfault.com/a/11...算法


http的定义

HTTP是基于客户端/服务端(C/S)的架构模型,经过一个可靠的连接来交换信息,是一个无状态的请求/响应协议。

http的结构

clipboard.png

咱们目前用到最多的是http1.x协议,header和body咱们都不陌生,那么startline是什么呢?startline是咱们所说的request_line或status_line,也就是
GET /HTTP/1.1或者HTTP/1.1 200 OK这种字段。
在叙述http的各类工做方式以前,咱们先熟悉一下TCP/IP模型:segmentfault

clipboard.png

http的发展:

http1.0

Http1.0:http1.0是默认没有keep-alive的,在数据请求的时候会先进性应用层如下的处理过程才会到应用层,在这里咱们只说传输层和应用层,在http1.0中,每一次的请求都会进行创建tcp链接(三次握手),而后进行http请求,这样每次与服务器交互,都须要新开一个链接!咱们的每一个连接的请求链路都以下图所示:浏览器

clipboard.png

想象一下,每发起一个请求就通过上述如此长的一个流程,这将耗去多少资源。缓存

http1.1

基于这个问题,咱们的http迎来了http1.1版本,1.1版本相对于1.0版本有什么改动呢?安全

  • http增长了host字段
  • HTTP 1.1中引入了Chunked transfer-coding,范围请求,实现断点续传(实际上就是利用HTTP消息头使用分块传输编码,将实体主体分块传输)
  • HTTP 1.1管线化(pipelining)理论,客户端能够同时发出多个HTTP请求,而不用一个个等待响应以后再请求服务器

    • 注意:这个pipelining仅仅是限于理论场景下,大部分桌面浏览器仍然会选择默认关闭HTTP pipelining!
    • 因此如今使用HTTP1.1协议的应用,都是有可能会开多个TCP链接的!

Http1.1基于上述耗费资源的问题给予了根本的处理,默认长连接,什么意思呢? 不去在每个http请求的时候都去进行http链接,只创建一个tcp连接去处理多个请求,固然,这里的每一个请求是串行的,即只是不用去进行tcp链接,仍是得排队,而且这样子可能会引发线头阻塞(例如发送100个请求,第一个被阻塞致使后边99个也不能请求)问题。对于http1.1默认的工做模式以下图所示:网络

clipboard.png

到这咱们想象一下这种模式好么,有什么缺点?能够优化吗?
在此之上咱们已经抛出了两个问题1.须要排队 2.可能引发线头阻塞。对于第一个问题,http1.1已经给出了解决方案,即pipline,而第二个问题刚开始有一种过渡的方案,即spdy协议(google推出的一项加强http的协议,功能包括数据流的多路复用、请求优先级以及HTTP报头压缩,有兴趣的能够研究一下),而后再到如今的http2.0。
首先咱们先说一下什么是pipline,pipline是一项实现了多个http请求但不须要等待响应就可以写进同一个socket的技术,仅有http1.1规范支持http管线化,1.0并不支持。什么意思呢?咱们看上图是在一个tcp链接的串行的去处理,那么开启了pipline以后就会变成下边这个样子:架构

clipboard.png

咱们能够看到发送http请求再也不是先发送而后等待response再发送下个请求了,这样子咱们能够当作是全部的请求统一开始,可是这有一个问题,HTTP Pipelining实际上是把多个HTTP请求放到一个TCP链接中一一发送,而在发送过程当中不须要等待服务器对前一个请求的响应;只不过,客户端仍是要按照发送请求的顺序来接收响应!这就致使了它虽然解决了排队问题,可是他也仅仅是解决了单方排队的问题,最后接受数据仍是按照请求的顺序来接受相应,为何呢?由于他们不知道哪一个是第一个哪一个是第二个。这样一样会存在线头阻塞的问题。
总结一下就是在http1.0的时候咱们是流水线,一个接一个的完成任务,http1.1的时候呢咱们工人的能力提高了,能够一次发出多个工做需求了,可是尚未掌握技巧,仍是得按照条例等待工做所有到来的时候一个一个按顺序处理。socket

http2.0

接下来就是咱们的http2.0,看他如何解决了以前的问题。解决线头阻塞,在http2.0中实际上是用了一个stream的结构,给每个stream分配一个标示即streamId就能够来解决线头阻塞的问题。那么http2到底是何方神圣呢?
首先,提及http2,咱们不得不提一下https,http2是基于https的一个协议,对于https我找了一篇写的比较好的文章,Wireshark 抓包理解 HTTPS 请求流程
文章开头咱们对比了http1和http2的结构,看起来好像彻底不同,可是实际上并不是如此,http2以帧做为最小单位,看了下边的图咱们会发现原来http2只是作了层封装,其实本质仍是headers和body,只不过http2是以更高级功能更多的方式进行了展现。tcp

clipboard.png

http1.x vs http2.0

关于http2好在哪里,那咱们得从http1坏出发,由于有对比才会有伤害。

  • http1链接数限制,对于同一个域名,浏览器最多只能同时建立 6~8 个 TCP 链接 (不一样浏览器不同)。为了解决数量限制,出现了 域名分片 技术,其实就是资源分域,将资源放在不一样域名下 (好比二级子域名下),这样就能够针对不一样域名建立链接并请求,以一种讨巧的方式突破限制,可是滥用此技术也会形成不少问题,好比每一个 TCP 链接自己须要通过 DNS 查询、三步握手、慢启动等,还占用额外的 CPU 和内存,对于服务器来讲过多链接也容易形成网络拥挤、交通阻塞等。那么,http2是怎么作的呢?http2采用了多路复用技术,在一个 TCP 链接上,咱们能够向对方不断发送帧,每帧的 stream_id标明这一帧属于哪一个流,而后在对方接收时,根据 stream_id拼接每一个流的全部帧组成一整块数据。把 HTTP/1.1 每一个请求都看成一个流,那么多个请求变成多个流,请求响应数据分红多个帧,不一样流中的帧交错地发送给对方,这就是 HTTP/2 中的多路复用。同时呢,咱们知道http1的body长度是在header带过来的,那么若是是以http2的形式去传输确定会出问题,因此http2将body上架了length字段,每个流都有本身的长度,最后根据流的头部长度是否等于各个流的长度来肯定是否合包。同时呢,这样分包合包也解决了线头阻塞的问题。那么问题又来了,怎么肯定没有丢包?同一个stream秩序有没有乱?这点tcp会保证包的有序性且保证了包不会丢失。
  • Header 内容多,并且每次请求 Header 不会变化太多,没有相应的压缩传输优化方案。http2在此用hpack算法来压缩首部长度,其原理就是维护一个静态索引表和动态索引表的索引空间,hpack其原理就是匹配当前链接存在的索引空间,若某个键值已存在,则用相应的索引代替首部条目,好比 “:method: GET” 能够匹配到静态索引中的 index 2,传输时只须要传输一个包含 2 的字节便可;若索引空间中不存在,则用字符编码传输,字符编码能够选择哈夫曼编码,而后分状况判断是否须要存入动态索引表中,以这种形式节省了不少的空间。
  • 明文传输不安全。http1使用明文传输,不安全。那么http2就用二进制分帧层来解决这个问题,帧是数据传输的最小单位,以二进制传输代替本来的明文传输,本来的报文消息被划分为更小的数据帧。
  • 为了尽量减小请求数,须要作合并文件、雪碧图、资源内联等优化工做,可是这无疑形成了单个请求内容变大延迟变高的问题,且内嵌的资源不能有效地使用缓存机制。对于这种状况,http2推出了服务端推送,浏览器发送一个请求,服务器主动向浏览器推送与这个请求相关的资源,这样浏览器就不用发起后续请求,其主要是针对资源内联作出的优化。
  • 应用层的重置链接,对于 HTTP/1 来讲,是经过设置 tcp segment 里的 reset flag 来通知对端关闭链接的。这种方式会直接断开链接,下次再发请求就必须从新创建链接。HTTP/2 引入 RST_STREAM 类型的 frame,能够在不断开链接的前提下取消某个 request 的 stream,表现更好。

扩展

关于http咱们就说这么多,若是想了解的更多读者能够自行用wireshark抓包看一下。推荐两个比较好的抓包工具:wireshark和charles。

参考文章: