HTTP/1.1 vs HTTP/2区别是什么

翻译自:https://www.digitalocean.com/community/tutorials/http-1-1-vs-http-2-what-s-the-difference

本文主要使用www.DeepL.com/Translator翻译(免费版)后修改

 

介绍

超文本传输协议,或称HTTP,是一种应用协议,自1989年发明以来,一直是万维网通信的事实上的标准。

从1997年HTTP/1.1的发布到最近,对该协议的修订很少。

但在2015年,一个被称为HTTP/2重新设计的版本投入使用,它提供了几种减少延迟的方法,特别是在处理移动平台和服务器密集型图形和视频时。

此后,HTTP/2变得越来越流行,一些估计表明,世界上大约三分之一的网站都支持它。

在这种不断变化的情况下,网络开发人员可以从了解HTTP/1.1和HTTP/2之间的技术差异中受益,使他们能够对不断发展的最佳实践作出明智和有效的决定。

阅读本文后,你将了解HTTP/1.1和HTTP/2之间的主要区别,集中于HTTP/2为实现更有效的网络协议而采取的技术变革。

背景

为了了解HTTP/2对HTTP/1.1所做的具体改变,让我们先高屋建瓴地看看各自的历史发展和基本运作情况。

HTTP/1.1

由Timothy Berners-Lee在1989年开发,作为万维网的通信标准,HTTP是一个顶级的应用协议,在客户端计算机和本地或远程网络服务器之间交换信息。
在这个过程中,客户端通过调用GET或POST等方法向服务器发送一个基于文本的请求。

作为回应,服务器发送一个资源,如一个HTML页面,返回给客户端。

例如,假设你正在访问一个域名为www.example.com 的网站。

当你导航到这个URL时,你电脑上的网络浏览器会以文本信息的形式发送一个HTTP请求,类似于这里显示的内容。

GET /index.html HTTP/1.1
Host: www.example.com

这个请求使用GET方法,它要求在Host:之后的主机服务器列表中获取数据。

作为对这个请求的回应,example.com网络服务器将一个HTML页面返回给请求的客户端,此外还有任何图像、样式表或HTML中调用的其他资源。

请注意,在第一次调用数据时,并非所有的资源都返回给客户端。

请求和响应将在服务器和客户端之间来回进行,直到网络浏览器收到所有必要的资源,在你的屏幕上呈现HTML页面的内容。

你可以把这种请求和响应的交换看作是互联网协议栈的单一应用层,位于传输层(通常使用传输控制协议,即TCP)和网络层(使用互联网协议,即IP)之上。

关于这个堆栈的较低层次,还有很多要讨论的,但为了获得对HTTP/2的高层次理解,你只需要知道这个抽象的层模型以及HTTP在其中的地位。

通过对HTTP/1.1的基本概述,我们现在可以继续叙述HTTP/2的早期发展。

HTTP/2

HTTP/2开始是SPDY协议,主要在谷歌开发,目的是通过使用压缩、多路复用和优先级等技术来减少网页加载延迟。

当IETF(互联网工程任务组)的超文本传输协议工作组httpbis把标准放在一起时,这个协议成为了HTTP/2的模板,最终在2015年5月发布了HTTP/2。

从一开始,许多浏览器就支持这项标准化工作,包括Chrome、Opera、Internet Explorer和Safari。

自2015年以来,该协议的采用率很高,一部分是因为浏览器的支持,在新网站中采用率尤其高。

从技术角度来看,区分HTTP/1.1和HTTP/2的最重要特征之一是二进制框架层,它可以被认为是互联网协议栈中应用层的一部分。

与HTTP/1.1相比,HTTP/2使用二进制框架层将所有消息封装成二进制格式,同时仍然保持HTTP的语义,如动词、方法和头文件。

应用层的API仍然会以传统的HTTP格式创建消息,但底层会将这些消息转换为二进制。

这确保了在HTTP/2之前创建的网络应用在与新协议互动时可以继续正常运行。

将消息转换为二进制允许HTTP/2尝试HTTP/1.1中没有的新的数据传递方式,这种对比是这两个协议之间实际差异的根源。

下一节将看一下HTTP/1.1的交付模式,然后是HTTP/2使哪些新模式成为可能。

 传输模型

正如上一节所提到的,HTTP/1.1和HTTP/2共享语义。

确保在这两个协议中,服务器和客户端之间的请求和响应作为传统格式的消息,使用GET和POST等熟悉的方法,到达目的地。

但是,当HTTP/1.1以纯文本信息传输这些信息时,HTTP/2将这些信息编码为二进制,允许明显不同的传输模型成为可能。

在这一节中,我们将首先简要研究HTTP/1.1如何试图通过其传输模型来优化效率,以及由此产生的问题,

然后是HTTP/2的二进制框架层的优势,以及它如何对请求进行优先排序的描述。

HTTP/1.1--流水线和行首阻断

客户端在HTTP GET请求中收到的第一个响应通常不是完全呈现的页面。

相反,它包含了请求页面所需的额外资源的链接。

客户端在下载页面后才发现,页面的完整呈现需要服务器提供这些额外资源。

正因为如此,客户端将不得不发出额外的请求来检索这些资源。

在HTTP/1.0中,客户端不得不在每一个新的请求中中断并重做TCP连接,这在时间和资源上都是一个昂贵的事情。

HTTP/1.1通过引入持久连接和流水线处理了这个问题。

通过持久连接,HTTP/1.1假定TCP连接应该保持开放,除非直接被告知关闭。

这使得客户端可以沿着同一连接发送多个请求,而不需要等待每个请求的响应,从而在HTTP/1.0的基础上大大改善了HTTP/1.1的性能。

不幸的是,这种优化策略有一个自然瓶颈。

由于多个数据包在前往同一目的地时不能相互传递,所以在有些情况下,排在队首的请求如果不能检索到它所需要的资源,就会阻塞后面的所有请求。

这就是所谓的行首(HOL)阻塞,是HTTP/1.1中优化连接效率的一个重要问题。

增加单独的、平行的TCP连接可以缓解这个问题,但是客户端和服务器之间可能的并发TCP连接数量是有限的,而且每个新连接都需要大量的资源。

这些问题是HTTP/2开发者的首要任务,他们提议使用上述的二进制框架层来解决这些问题,你将在下一节中了解更多的主题。

HTTP/2 - 二进制框架层的优势

在HTTP/2中,二进制框架层对请求/响应进行编码,并将其切割成更小的信息包,大大提高了数据传输的灵活性。

让我们仔细看看这是如何工作的。

与必须利用多个TCP连接来减少HOL阻塞的影响的HTTP/1.1相反,HTTP/2在两台机器之间建立了一个单一的连接对象。

在这个连接中,有多个数据流。

每个数据流由多个相似的请求/响应格式的消息组成。

最后,这些消息中的每一条都被分割成较小的单元,称为帧。

在最微观的层面上,通信通道由一堆二进制编码的帧组成,每个帧都被标记在一个特定的流。

识别标签允许连接在传输过程中交错这些帧,并在另一端将其重新组合。

交错的请求和响应可以并行运行,而不会阻断后面的信息,这个过程称为复用。

复用解决了HTTP/1.1中的行首阻塞问题,确保没有消息需要等待另一个消息完成。

这也意味着服务器和客户端可以同时发送请求和响应,允许更大的控制和更有效的连接管理。

由于多路复用允许客户端并行构建多个数据流,这些数据流只需要利用一个TCP连接。

每个来源有一个持久的连接,通过减少整个网络的内存和处理足迹,改善了HTTP/1.1。

这带来了更好的网络和带宽利用率,从而降低了整体运营成本。

单一的TCP连接也提高了HTTPS协议的性能,因为客户端和服务器可以为多个请求/响应重复使用同一个安全会话。

在HTTPS中,在TLS或SSL握手期间,双方同意在整个会话中使用一个单一的密钥。

如果连接中断,新的会话开始,需要一个新生成的密钥来进行进一步的通信。

因此,维持一个单一的连接可以大大减少HTTPS性能所需的资源。

请注意,尽管HTTP/2规范没有强制要求使用TLS层,但许多主要浏览器只支持HTTPS的HTTP/2。

尽管二进制框架层中固有的多路复用解决了HTTP/1.1的某些问题,但多个流等待同一资源仍然会导致性能问题。

然而,HTTP/2的设计通过使用流优先级考虑到了这一点,我们将在下一节讨论这一问题。

HTTP/2 流优先级

流优先级不仅解决了请求竞争同一资源的可能问题,而且允许开发人员定制请求的相对权重,以更好地优化应用性能。

在本节中,我们将分解这种优先级的过程,以便更好地了解你如何利用HTTP/2的这一功能。

正如你现在所知,二进制框架层将消息组织成平行的数据流。

当客户端向服务器发送并发请求时,它可以通过给每个数据流分配1到256的权重来确定它所请求的响应的优先级。

数字越大表示优先级越高。

除此以外,客户端还通过指定它所依赖的流的ID来说明每个流对另一个流的依赖性。

如果省略了父标识符,该流就被认为是依赖于根流。

这在下图中得到了说明。

在图中,通道包含六个流,每个流都有一个唯一的ID,并与一个特定的权重相关。

流1没有与之相关的父ID,默认与根节点相关。

所有其他的流都有一些父ID标记。

每个流的资源分配将基于它们持有的权重和它们需要的依赖关系。

例如,流5和流6,在图中被分配了相同的权重和相同的父流,将有相同的资源分配优先级。

服务器使用这些信息来创建一个依赖树,这使得服务器能够确定请求检索其数据的顺序。基于上图中的数据流,依赖树将如下所示。

 

在这个依赖树中,流1依赖于根流,没有从根流派生出来的其他流,所以所有可用的资源都将分配给流1,领先于其他流。

由于该树表明流2依赖于流1的完成,所以流2在流1的任务完成之前不会进行。

现在,让我们看一下流3和流4。这两个流都依赖于流2。

与流1的情况一样,流2将在流3和流4之前获得所有可用的资源。

在流2完成其任务后,流3和流4将获得资源;

如其权重所示,这些资源按2:4的比例分配,结果是流4获得了更多的资源。

最后,当流3完成时,流5和流6将以相等的部分获得可用的资源。

这可能发生在流4完成其任务之前,尽管流4获得了更多的资源;低层的流被允许在上层的依赖流完成后立即开始。

作为一个应用程序的开发者,你可以根据你的需要来设置请求中的权重。

例如,你可以在网页上提供一个缩略图后,为加载一个高分辨率的图像指定一个较低的优先级。

通过提供这种权重分配的便利,HTTP/2使开发者能够更好地控制网页渲染。

该协议还允许客户端在运行时改变依赖关系并重新分配权重,以响应用户的互动。

然而,需要注意的是,如果某个流被阻止访问特定资源,服务器可以自行改变分配的优先级。

缓存溢出

在两台机器之间的任何TCP连接中,客户端和服务器都有一定量的缓冲空间可用来容纳尚未处理的传入请求。

这些缓冲区为众多或特别大的请求提供了灵活性,此外,下游和上游连接的速度也不平衡。

然而,在有些情况下,缓冲区是不够的。

例如,服务器可能以客户端应用程序无法应付的速度推送大量数据,因为缓冲区大小有限或带宽较低。

同样,当客户端向服务器上传一张巨大的图片或视频时,服务器的缓冲区可能会溢出,导致一些额外的数据包被丢失。

为了避免缓冲区溢出,流量控制机制必须防止发送方用数据淹没接收方。

本节将概述HTTP/1.1和HTTP/2如何根据其不同的交付模式使用不同版本的该机制来处理流量控制问题。

HTTP/1.1

在HTTP/1.1中,流量控制依赖于基础的TCP连接。

当该连接启动时,客户端和服务器都使用其系统默认设置建立其缓冲区大小。

如果接收方的缓冲区被数据部分填满,它将告诉发送方其接收窗口,即其缓冲区中剩余的可用空间量。

这个接收窗口在一个被称为ACK包的信号中公布,ACK包是接收器发送的数据包,以确认它收到了开放信号。

如果这个公告的接收窗口大小为零,发送方将不再发送数据,直到客户端清除其内部缓冲区,然后请求恢复数据传输。

这里需要注意的是,使用基于底层TCP连接的接收窗口,只能在连接的某一端实现流量控制。

因为HTTP/1.1依靠传输层来避免缓冲区溢出,每个新的TCP连接都需要一个单独的流量控制机制。

然而,HTTP/2在一个单一的TCP连接中复用流,将不得不以不同的方式实现流量控制。

HTTP/2

HTTP/2在一个单一的TCP连接中复用数据流。

因此,TCP连接层面的接收窗口不足以调节单个数据流的交付。

HTTP/2通过允许客户端和服务器实现自己的流量控制,而不是依赖传输层来解决这个问题。

应用层传达可用的缓冲空间,允许客户端和服务器在复用流的层面上设置接收窗口。

这种细粒度的流控制可以在初始连接后通过WINDOW_UPDATE帧进行修改或维护。

由于这种方法在应用层层面控制数据流,流量控制机制不必等待信号到达其最终目的地后再调整接收窗口。

中介节点可以使用流量控制设置信息来确定自己的资源分配并进行相应的修改。

通过这种方式,每个中间服务器可以实现自己的自定义资源策略,从而实现更大的连接效率。

在创建适当的资源策略时,流量控制的这种灵活性可能是有利的。

例如,客户端可以获取图像的第一次扫描,将其显示给用户,并允许用户预览,同时获取更多关键资源。

一旦客户端获取了这些关键资源,浏览器将恢复对图像剩余部分的检索。

因此,将流控制的实现推迟到客户端和服务器,可以提高网络应用的感知性能。

就流量控制和前一节提到的流优先级而言,HTTP/2提供了一个更详细的控制水平,为更大的优化提供了可能。

下一节将解释该协议特有的另一种方法,可以以类似的方式增强连接:用服务器推送预测资源请求。

预测资源请求

在一个典型的网络应用中,客户端将发送一个GET请求,并收到一个HTML页面,通常是网站的索引页。

在检查索引页的内容时,客户端可能会发现它需要获取额外的资源,如CSS和JavaScript文件,以便完全呈现该页面。

客户端在收到最初的GET请求的响应后才确定它需要这些额外的资源,因此必须发出额外的请求来获取这些资源并完成页面的拼接。

这些额外的请求最终会增加连接的加载时间。

然而,这个问题是有解决办法的:由于服务器事先知道客户端将需要额外的文件,服务器可以通过在客户端请求之前将这些资源发送给客户端来节省时间。

HTTP/1.1和HTTP/2有不同的策略来实现这一点,每一种策略将在下一节描述。

HTTP/1.1——内联资源

在HTTP/1.1中,如果开发者事先知道客户端机器需要哪些额外的资源来渲染页面,

他们可以使用一种叫做资源内联的技术,将所需的资源直接包含在服务器响应最初的GET请求而发送的HTML文档中。

例如,如果客户端需要一个特定的CSS文件来渲染页面,内联该CSS文件将在客户端请求之前为其提供所需的资源,从而减少客户端必须发送的请求总数。

但是,资源内联也有一些问题。

对于较小的、基于文本的资源来说,将资源包含在HTML文档中是一个可行的解决方案,

但较大的非文本格式的文件会大大增加HTML文档的大小,这最终会降低连接速度,使使用这种技术获得的原始优势化为乌有。

另外,由于内联资源不再与HTML文档分开,因此没有机制让客户端拒绝它已经拥有的资源,或将资源放入其缓存。

如果多个页面都需要该资源,那么每个新的HTML文档都会在其代码中内联相同的资源,从而导致HTML文档变大,加载时间也比一开始就简单地缓存该资源的情况要长。

那么,资源内联的一个主要缺点是,客户端不能将资源和文档分开。需要更精细的控制来优化连接,HTTP/2试图通过服务器推送来满足这一需求。

HTTP/2服务端推送

由于HTTP/2能够对客户端的初始GET请求做出多个并发响应,服务器可以将资源与请求的HTML页面一起发送给客户端,在客户端要求之前提供资源。

这个过程被称为服务器推送。

通过这种方式,HTTP/2连接可以实现资源内联的相同目标,同时保持推送资源和文档之间的分离。

这意味着客户端可以决定缓存或拒绝推送的资源与主要的HTML文档分开,解决了资源内联的主要缺点。

在HTTP/2中,当服务器发送一个PUSH_PROMISE帧来通知客户端它要推送一个资源时,这个过程就开始了。

这个框架只包括消息的标题,并允许客户端提前知道服务器将推送哪个资源。

如果它已经缓存了该资源,客户端可以通过发送RST_STREAM帧作为响应来拒绝推送。

PUSH_PROMISE帧还可以使客户端避免向服务器发送重复的请求,因为它知道服务器将推送哪些资源。

这里需要注意的是,服务器推送的重点是客户端控制。

如果客户端需要调整服务器推送的优先级,甚至禁用它,它可以在任何时候发送一个SETTINGS帧来修改这个HTTP/2功能。

虽然这个功能有很大的潜力,但服务器推送并不总是优化网络应用的答案。

例如,一些网络浏览器不是一直能取消推送的请求,即使客户端已经有了资源的缓存。

如果客户端错误地允许服务器发送重复的资源,服务器推送会不必要地占用连接。

最后,服务器推送的使用应该由开发者决定。

关于如何战略性地使用服务器推送和优化网络应用的更多信息,请查看谷歌开发的PRPL模式

要了解更多关于服务器推送可能出现的问题,请看Jake Archibald的博文HTTP/2推送比我想象的要难。 

压缩

优化网络应用的一个常见方法是使用压缩算法来减少客户端和服务器之间的HTTP消息的大小。

HTTP/1.1和HTTP/2都使用这种策略,但前者存在实施问题,禁止压缩整个消息。

下一节将讨论为什么会出现这种情况,以及HTTP/2如何提供解决方案。

HTTP/1.1

像gzip这样的程序长期以来一直被用来压缩HTTP消息中发送的数据,特别是用来减少CSS和JavaScript文件的大小。

然而,消息的头部分总是以纯文本形式发送。

虽然每个头都相当小,但随着请求的增多,这些未压缩的数据对连接的负担越来越重,

特别是对复杂的、需要许多不同资源的API重的网络应用的,因此也就有许多不同的资源请求。

此外,使用cookies有时会使头文件变得更大,增加了对某种压缩的需要。

为了解决这个瓶颈,HTTP/2使用HPACK压缩来缩小头文件的大小,这个话题在下一节进一步讨论。

 HTTP/2

在HTTP/2中一再出现的主题之一,是它能够使用二进制框架层来表现出对更细粒度的细节的更大控制。

在涉及到头的压缩时也是如此。

HTTP/2可以从其数据中分离出头,形成一个头帧和一个数据帧。

然后,HTTP/2特定的压缩程序HPACK可以压缩这个头帧。

这种算法可以使用Huffman编码对头的元数据进行编码,从而大大减少了其大小。

此外,HPACK可以跟踪以前传达的元数据字段,并根据客户端和服务器之间共享的动态改变的索引进一步压缩它们。

例如,以下面两个请求为例。

method:     GET
scheme:     https
host:       example.com
path:       /academy
accept:     /image/jpeg
user-agent: Mozilla/5.0 ...
method:     GET
scheme:     https
host:       example.com
path:       /academy/images
accept:     /image/jpeg
user-agent: Mozilla/5.0 ...

这些请求中的各个字段,如method, scheme, host, accept, user-agent具有相同的值;只有路径字段使用不同的值。

因此,当发送第2号请求时,客户端可以使用HPACK只发送重建这些普通字段和新编码路径字段所需的索引值。

由此产生的头帧将如下。

method:     GET
scheme:     https
host:       example.com
path:       /academy
accept:     /image/jpeg
user-agent: Mozilla/5.0 ...
path:       /academy/images

使用HPACK和其他压缩方法,HTTP/2又提供了一个可以减少客户端-服务器延迟的功能。

总结

从这个逐点分析中可以看出,HTTP/2与HTTP/1.1有很多不同之处,

有些功能提供了更高的控制水平,可以用来更好地优化Web应用的性能,而其他功能只是在以前的协议基础上进行改进。

现在你已经对这两个协议之间的变化有了一个高层次的看法,你可以考虑HTTP/2中的复用、流优先级、流量控制、服务器推送和压缩等因素将如何影响网络开发的变化。

如果你想看看HTTP/1.1和HTTP/2之间的性能比较,请看这个Google demo,它对不同延迟的协议进行了比较。

请注意,当你在你的电脑上运行测试时,页面加载时间可能会有所不同,这取决于几个因素,如带宽、测试时可用的客户端和服务器资源,等等。

如果你想研究更详尽的测试结果,请看文章《HTTP/2 – A Real-World Performance Test and Analysis》。

最后,如果你想探索如何建立一个现代网络应用程序,你可以跟随我们的《 How To Build a Modern Web Application to Manage Customer Information with Django and React on Ubuntu 18.04》教程,

或者用我们的《 How To Set Up Nginx with HTTP/2 Support on Ubuntu 16.04》教程建立你自己的HTTP/2服务器。

posted on 2021-12-28 18:08  褐鹤  阅读(807)  评论(0编辑  收藏  举报

导航