版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/caomage/article/details/101148656
HTTP2.0可以让我们的应用更快、更简单、更健壮!HTTP2.0把很多以前我们针对HTTP1.1想出来的歪招都一笔勾销,把解决那些问题的方案都内置在了传输层中。
HTTP2.0的目的就是通过支持请求与相应的多路复用来减少延迟,通过压缩HTTP首部字段将协议开销降至最低,同时增加对请求优先级的服务器推送的支持。
HTTP2.0不会改动HTTP的语义。HTTP方法、状态、URI及首部字段,这些核心概念一如往常。
SPDY是谷歌开发的一个实验性协议,于2009年年中发布,其主要目标是通过解决HTTP1.1中广为人知的一些性能限制,来减少网页的加载延迟。SPDY引入了一个新的二进制分帧数据层,以实现多向请求和响应、优先次序、最小化及消除不必要的网络延迟,目的是更有效利用底层TCP连接。
几年后的2012年,这个新的实验性协议得到了Chrome、Firefox和Opera的支持,很多大型网站都对兼容客户端提供SPDY会话。换句话说,SPDY在被行业采用并证明能够大幅提升性能值周,已经具备了成为一个标准的条件。最终,HTTP-WG在2012年吸取了SPDY的经验教训,并在此基础上制定了官方标准。
SPDY是HTTP2.0的催化剂,但是SPDY并非HTTP2.0。以下是HTTP2.0宣言草稿,这份宣言明确了该协议的范围和关键设计要求:
HTTP1.x的设计初衷主要是实现要简单:HTTP0.9只用一行协议就启动了万维网;然而实现简单是以牺牲应用性能为代价的,而这正是HTTP2.0要致力与解决的。HTTP2.0通过支持首部字段压缩和在同一连接上发送多个并发消息,让应用更有效的利用网络资源,减少感知的延迟时间。而且,它还支持服务器到客户端的主动推送机制。
HTTP2.0性能增强的核心,全在于新增的二进制分帧层,它定义了如何封装HTTP消息并在客户端与服务器之间传输。这里所谓的“层”,指的是位于套接字接口与应用可见高层HTTP API之间的一个新机制:HTTP语义,包括各种动词、方法、首部,都不受影响,不同的是传输期间对它们的编码方式变了。HTTP1.x以换行符作为纯文本的分隔符,而HTTP2.0将所有传输的信息分割为更小的消息和帧,并对它们采用二进制格式的编码。
这样一来,客户端和服务器为了相互理解,必须都使用新的二进制编码机制:HTTP1.x客户端无法理解只支持HTTP2.0的服务器,反之亦然。不过不要紧,现有的应用不必担心这些变化,因为客户端和服务器会替它们完成必要的分帧工作。
HTTPS是二进制分帧的另一个典型示例:所有HTTP消息都以透明的方式为我们编码和解码,从而实现客户端与服务器安全通信,但不必对应用进行任何修改。HTTP2.0的工作原理差不多也是这样。
新的二进制分帧机制改变了客户端与服务器之间交互数据的方式。为了说明这个过程,我们需要了解HTTP2.0的几个新概念:
流 已建立的连接上的双向字节流。 消息 与逻辑消息对应的完整的一系列数据帧。 帧 HTTP2.0通信的最小单位,每个帧包含帧首部,至少也会标识出当前帧所属的流。
HTTP2.0通信都在一个连接上完成,这个连接可以承载任意数据量的双向数据流。相应地,每个数据流以消息的形式发送,而消息由一或多个帧组成,这些帧可以乱序发送,然后再根据每个帧首部的流标识符重新组装。HTTP2.0的所有帧都采用二进制编码,所有首部数据都会被压缩。
这简简单单的几句话里浓缩了大量的信息:
简言之,HTTP2.0把HTTP协议通信的基本单位缩小为一个一个的帧,这些帧对应着逻辑流中的消息。相应地,很多流可以并行的在同一个TCP连接上交换消息。
在HTTP1.x中,如果客户端想发送多个并行的请求以及改进性能,那么必须使用多个TCP连接。这是HTTP1.x交付模型的直接结果,该模型会保证每个连接每次只交付一个响应(多个响应必须排队)。更糟糕的是,这种模型也会导致队首阻塞,从而造成底层TCP连接的效率低下。
HTTP2.0中新的二进制分帧层突破了这些限制,实现了多向请求和响应:客户端和服务器可以把HTTP消息分解为互不依赖的帧,然后乱序发送,最后再在另一端把它们重新组合起来。
把HTTP消息分解为独立的帧,交错发送,然后在另一端重新组装是HTTP2.0最重要的一项增强。事实上,这个机制会在整个Web技术栈中引发一系列连锁反应,从而带来巨大的性能提升,因为:
总之,HTTP2.0的二进制分帧机制解决了HTTP1.x中存在的队首阻塞问题,也消除了并行处理和发送请求及响应时对多个连接的依赖。结果就是应用速度更快、开发更简单、部署成本更低。
支持多向请求和响应,可以省掉对HTTP1.x限制所费的那些工作,比如拼接文件、图片精灵、域名分区。类似地,通过减少TCP连接的数量,HTTP2.0也会减少客户端和服务器的CPU及内存占用。
把HTTP消息分解为很多独立的帧之后,就可以通过优化这些帧的交错和传输顺序,进一步提升性能。为了做到这一点,每个流都可以带有一个31比特的优先值:
0表示最高优先级; (2^31)-1表示最低优先级。
有了这个优先值,客户端和服务器就可以在处理不同的流时采用不同的策略,以最优的方式发送流、消息和帧。具体来讲,服务器可以根据流的优先级,控制资源分配(CPU、内存、带宽),而在响应数据准备好之后,优先将高优先级的帧发送给客户端。
浏览器在渲染页面时,并非所有资源都具有相同的优先级:HTML文档本身对构建DOM不可或缺,CSS对构建CSSOM不可或缺,而DOM和CSSOM的构建都可能会受到JavaScript资源的阻塞,其他资源(如图片)的优先级都可以降低。为加快页面加载的速度,所有现代浏览器都会基于资源的类型以及它在页面中的位置排定请求的优先次序,甚至通过之前的访问来学习优先级模式–比如,之前的渲染如果被某些资源阻塞了,那么同样的资源在下一次访问时可能就会被赋予更高的优先级。
有了新的分帧机制后,HTTP2.0不再依赖多个TCP连接去实现多流并行了。现在,每个数据流都拆分成很多帧,而这些帧可以交错,还可以分别优先级。于是,所有HTTP2.0连接都是持久化的,而且客户端与服务器之间也只需要一个连接即可。
每个来源一个连接显著减少了相关资源的占用:连接路径上的套接字管理工作量少了,内存占用少了,连接的吞吐量大了。此外,从上到下所有层面上也都获得了相应的好处:
在同一个TCP上传输多个数据流,就意味着要共享带宽。标定数据流的优先级有助于按序交付,但只有优先级还不足以确定多个数据流或多个连接间的资源分配。为解决这个问题,HTTP2.0为数据流和连接的流量控制提供了一个简单的机制:
HTTP2.0建立连接之后,客户端与服务器交换SETTINGS帧,目的是设置双向的流量控制窗口大小。除此之外,任何一端都可以选择禁用个别流或整个连接的流量控制。
HTTP2.0新增的一个强大的新功能,就是服务器可以对一个客户端请求发送多个响应。换句话说,除了对最初请求的响应外,服务器还可以额外想客户端推送资源,而无需客户端明确的请求。
建立HTTP2.0连接后,客户端与服务器交换SETTINGS帧,借此可以限定双向并发的流的最大数量。因此,客户端可以限定推送流的数量,或者通过设置为0而完全禁用服务器推送。
所有推送的资源都遵守同源策略。换句话说,服务器不能随便将第三方资源推送给客户端,而必须是经过双方确认才行。
HTTP的每次通信都会携带一组首部,用于描述传输的资源及其属性。在HTTP1.x中这些元数据都是以纯文本形式发送的,通常会给每个请求增加500-800字节的负担。如果算上Cookie,增加的负担更重。为减少这些,HTTP2.0会压缩首部元数据。 HTTP2.0在客户端和服务器端使用“首部表”来跟踪和存储之前发送的键值对,对于相同的数据,不再通过每次请求和响应发送; 首部表在HTTP2.0的连接存续期内始终存在,有客户端和服务器共同更新; 每个新的首部键值对要么被追加到当前表的末尾,要么替换表中之前的值。
于是,HTTP2.0连接的两端都知道已经发送了哪些首部。请求与响应首部的定义在HTTP2.0中基本没有改变,只是所有的首部健必须全部小写。
HTTP2.0的根本改进还是新增的长度前置的二进制分帧层。与HTTP1.x使用换行符分隔纯文本不同,二进制分帧层更加简洁,通过代码处理起来更简单也更有效。
建立了HTTP2.0连接后,客户端与服务器会通过交换帧来通信,帧是基于这个新协议通信的最小单位。所有帧都共享一个8字节的首部,其中包含帧的长度、类型、标志,还有一个保留位和一个31位的流标识符。
知道了HTTP2.0规定的这个共享的帧首部,就可以自己编写一个简单的解析器,通过分析HTTP2.0的字节流,根据每个帧的前8字节找到帧的类型、标识和长度。知道了帧类型,解析器就知道该如何解释帧的其余内容了。HTTP2.0规定了如下帧类型:
在发送应用数据之前,必须创建一个新流并随之发送相应的元数据,比如流优先级、HTTP首部等。HTTP2.0协议规定客户端和服务器都可以发起新流,因此有两种可能: 客户端通过发送HEADERS帧来发起新流,这个帧里包含有新流ID的公用首部、可选的31位优先值,以及一组HTTP键值对首部; 服务器通过PUSH_PROMISE帧来发起推送流,这个帧与HEADERS帧等效,但它包含要约流ID,没有优先值。
这两种帧的类型字段都只用于沟通新流的元数据,净荷会在DATA帧中单独发送。由于流的元数据与应用数据是单独发送的,因此客户端和服务器可以分别给他们设定不同的优先级。
创建并发送HTTP首部之后,接下来就是利用DATA帧发送应用数据。应用数据可以分为多个DATA帧,最后一帧要翻转帧首部的END_STREAM字段。
数据净荷不会被另行编码或压缩。编码方式取决于应用或服务器,纯文本、gzip压缩、图片或视频压缩格式都可以。
从技术上说,DATA帧的长度字段决定了每帧的数据净荷最多可大65535字节。可是,为了减少队首阻塞,HTTP2.0标准要求DATA帧不能超过16383字节。长度超过这个阈值的数据,就得分帧发送。