致谢

最后更新于:2022-04-01 20:52:50

# 14. 致谢 介绍数据包格式的乐高图片来自于Mark Nottingham,感谢他给我提供的灵感。 HTTP趋势数据来自[http://httparchive.org](http://httparchive.org)。 RTT图来自Mike Belshe的演讲。 感谢我的孩子Agnes和Rex,他们把乐高玩具借给我作为head of line的图片。 感谢以下为我提供校对和反馈的朋友:Kjell Ericson, Bjorn Reese, Linux Swalas和Anthony Bryan。是你们让这份文档变得更好! 在完成文档的过程中,以下朋友反馈了bug帮助改进文档:Mikael Olsson, Remi Gacogne, Benjamin Kircher, saivlis, florin-andrei-tp, Brett Anthoine, Nick Parlante, Matthew King, Nicolas Peels, Jon Forrest, sbrickey, Marcin Olak, Gary Rowe, Ben Frain, Mats Linander
';

扩展阅读

最后更新于:2022-04-01 20:52:48

# 13. 扩展阅读 如果对读者你来说,这份文档的内容或技术细节稍显浅尝辄止,下面的资源也许能满足你的好奇: - HTTPBis小组邮件列表和归档:[http://lists.w3.org/Archives/Public/ietf-http-wg/](http://lists.w3.org/Archives/Public/ietf-%20http-wg/) - 来自HTTPbis小组的http2标准草案和其相关文档:[http://datatracker.ietf.org/wg/httpbis/](http://datatracker.ietf.org/wg/httpbis/) - Firefox http2网络细节:[https://wiki.mozilla.org/Networking/http2](https://wiki.mozilla.org/Networking/http2) - curl http2实现细节:[http://curl.haxx.se/dev/readme-http2.html](http://curl.haxx.se/dev/readme-http2.html) - http2网站:[http://http2.github.io/](http://http2.github.io/),以及关于http2的FAQ:[http://http2.github.io/faq/](http://http2.github.io/faq/)
';

后http2时代

最后更新于:2022-04-01 20:52:45

# 12. 后http2时代 http2做了许多艰难的折衷和妥协。随着http2逐渐部署,将会带来一个健全的协议升级方式,而这为将来更多的协议升级奠定了基础。同时,它也引入了一套概念和基础架构来并行处理多个不同版本协议。也许我们并不需要在引入新协议时完全地淘汰掉旧的。 http2仍然背负了许多HTTP1的历史包袱,主要是为了保证数据流量能够在HTTP1和http2之间无碍转发。这些包袱会阻碍进一步的的开发和创造,期待http3能丢掉其中一部分。 亲爱的读者,你认为http还缺少什么?
';

Curl里的http2

最后更新于:2022-04-01 20:52:43

# 11. curl中的http2 curl项目从2013年9月就开始对http2提供实验性的支持。 为了遵从curl的要旨,我们尽可能地支持http2的每个方面。curl通常被当作一个网站连接测试工具,希望这也能在http2上得以延续。 curl使用一个叫做[nghttp2](https://nghttp2.org/)的库来支持http2帧层的功能。 ## 11.1 跟HTTP 1.x非常相似 curl会在内部把收到的http2头部转换为HTTP1.x风格的头部再呈现给用户,这样一来,它们就和目前的HTTP非常类似。这也使得无论是用curl还是HTTP,转换都非常容易。类似地,curl会用相同的方式对发出的HTTP头部做转换,即发给curl的HTTP 1.x风格头部会在被发送到http2服务器之前完成转换。这使得户无需关心底层到底使用的是哪个版本的HTTP协议。 ## 11.2 不安全的纯文本 curl通过升级头部支持基于标准TCP的http2. 当发起一个使用http2的HTTP请求,如果可能,curl会请求服务器把连接升级到http2. ## 11.3 TLS和相关库 curl可以使用许多不同TLS的底层库来提供TLS支持,http2也得这样。TLS兼容http2的挑战来自于对APLN以及一些NPN扩展的支持。 基于最新版本的OpenSSL或NSS编译curl可以同时获得ALPN和NPN支持。而使用GnuTLS或PolarSSL只能得到ALPN。 ## 11.4 命令行中使用 无论是用纯文本还是通过TLS,必须使用`--http2`参数来让curl使用http2。默认未使用该参数的情况下,curl会使用HTTP/1.1。 ## 11.5 libcurl参数 应用程序和从前一样使用`https://`或者`http://`风格的URL,但你可以通过将`curl_easy_setopt`的`SURLOPT_HTTP_VERSION`参数设置为`CURL_HTTP_VERSION_2`来使libcurl尝试使用http2。它将优先尽可能地使用http2,如果不行的话,会继续使用HTTP 1.1。
';

Chromium里的http2

最后更新于:2022-04-01 20:52:41

# 10. Chromium里的http2 Chromium团队并且很早之前就已经在dev和beta分支里面实现并支持了HTTP/2。从2015年1月27日发布的Chrome 40起,http2已经默认为一些用户启用该功能。虽然刚开始用户的数量会很少,但会慢慢增加。 SPDY的支持将会被移除。在2015年2月的一篇[博客](http://blog.chromium.org/2015/02/hello-http2-goodbye-spdy-http-is_9.html)里面有如下一段话: > “Chrome自从6之后就开始支持SPDY,但既然现在它的优势已经被HTTP/2所取代, 现在是时候说再见了。我们计划在2016年早些时候移除对SPDY的支持” ## 10.1. 首先,确保它已被启用 在地址栏里进入`chrome://flags/#enable-spdy4`,如果没有被enable的话,点击"enable"启用它。 ## 10.2. TLS-only 请记住Chrome只在TLS上实现了http2。你只会在看到http2只在`https://`的网站里得到支持。 ## 10.3. 图形化HTTP/2 有一些Chrome的插件可以图形化HTTP/2,比如[SPDY Indicator](https://chrome.google.com/webstore/detail/spdy-indicator/mpbpobfflnpcgagjijhmgnchggcjblin)。
';

Firefox里的http2

最后更新于:2022-04-01 20:52:39

# 9. Firefox里的http2 Firefox紧跟着草案,并且很早之前就实现了http2的测试实现。在http2协议开发的时候,客户端和服务器需要采用同一的协议草案版本,进行测试也变得比较繁琐。所以请一定注意你的客户端和服务器支持的是一样的版本。 ## 9.1. 首先,确保它已被启用 从发布于2015年1月13日的Firefox 35之后,http2支持是默认开启的。 在地址栏里进入'about:config',再搜索一个名为“network.http.spdy.enabled.http2draft”的选项,确保它被设置为`true`。 ## 9.2. 仅限TLS 请记住Firefox只在TLS上实现了http2。你只会在看到http2只在`https://`的网站里得到支持。 ## 9.3. 透明! ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-08-09_55c75bc24eb04.png) _图示1:_ 截图表明Firefox正在使用http2 draft-12 在UI上,没有任何元素标明你正在使用http2。但想确认也并不复杂,一种方法是启用“Web developer->Network”,再查看响应头里面服务器发回来的内容。这个响应是“HTTP/2.0”,并且Firefox也插入了一个自己头“X-Firefox-Spdy:”,如上面截图所示。 你在这里看到的头文件是网络工具把二进制的http2格式转换成类似HTTP 1.x显示方式的文本格式。 ## 9.4. 图形化HTTP/2 有一些Firefox的插件可以图形化HTTP/2,比如[SPDY Indicator](https://addons.mozilla.org/en-US/firefox/addon/spdy-indicator/)。
';

http2的世界

最后更新于:2022-04-01 20:52:36

# 8. http2的世界 那么当http2被广泛采用的时候,世界会成怎么样呢?或者它会被广泛采用吗? ## 8.1. http2会如何影响普通人? 现在http2还没被大范围部署使用,我们也无法确定到底会发生什么变化,但至少可以参考SPDY的例子和曾经做过的实验来进行大概估计。 http2减少了网络往返传输的数量,并且用多路复用和快速丢弃不需要的流的办法来完全避免了head of line blocking的困扰。 它也支持大量并行流,所以即使网站的数据分发在各处也不是问题。 合理利用流的优先级,可以让客户端尽可能优先收到更重要的数据。 所有这些加起来,我认为页面载入时间和站点相应的速度都会更快。简而言之:更好的web体验。 但到底能变得多快,到底提升有多大呢?我认为目前很难说清楚。毕竟这些技术依然在早期,我们还没法看见客户端和服务器实现这些并真正受益于新协议所提供的强大功能。 ## 8.2. http2会如何影响web开发? 近年来,web开发者、web开发环境为一些HTTP 1.1的问题提供了临时解决方案。不妨回忆一下,其中一些我已在上文中简单的介绍了。 这些解决方案很多是工具和开发者默认使用的,这很可能会损害到http2的性能,或者至少让我们没法真正利用到http2新提供的强大威力。Spriting和内联应该是http2里面最不需要的了。因为http2更倾向于使用更少的连接,所以Sharding甚至会伤害到http2的性能。 这里的问题就是:web网站和web开发们至少在短期内需要同时支持HTTP 1.1和http2的客户端。否则的话,使所有用户获得最好的体验将是一个挑战。 考虑到这些问题,我认为距离http2的潜力被彻底发掘还有很长一段路要走。 ## 8.3. http2的实现 在这样一篇文章中详细说明每个实现细节注定乏味且毫无意义,我将用更广泛的术语解释实际场景,给大家提供一个http2的[实现列表](https://github.com/http2/http2-spec/wiki/Implementations)作为参考。 在http2的早期就已经有大量的实现。并且在http2标准化工作期间,这个数量还持续增长。截至我写这篇文档的时候,共有30种实现记录在案,他们中的大多数都实现了最新的草案。 Firefox一直紧跟最新的协议,Twitter也紧追不舍提供了基于http2的服务。2014年4月期间,Google在少数测试服务器上提供http2支持。从同年5月开始,开发版的Chrome支持http2。Microsoft也在他们的产品预发布会上展示了支持http2的下一代浏览器。 curl和libcurl支持未加密的http2,同时借助某些TLS库支持了TLS。 draft-17是当前最新的草案版本,它二进制兼容draft-14。后者是最近一个被标记为实现/互操作的草案。但是当draft-17 进行线上二进制兼容的时候,草案的语言的改变也造成了他们的些许不同。 **8.3.1. 缺失的实现** 现有的实现列表中仍然有明星品牌缺席。目前尚未听到Apple官方有让Safari支持http2的计划。Apache HTTPD和Nginx这两大流行的服务器都提供SPDY的支持,但却没有对提供http2的支持进行任何表态。 Nginx表示“我们计划于2015年末发布带有HTTP/2支持的nginx和NGINX Plus”。而Apache已经有一个非常早期的HTTP/2模块,叫作[mod_h2](https://icing.github.io/mod_h2/)。 ## 8.4. 对http2的常见批评 在制定协议的讨论过程中有许多充满争议的地方,甚至会有不少人认为这样的协议最终会以失败告终。这里我想提一些对协议常见的批评和我的解释: **8.4.1. “这个协议是Google设计制定的”** 江湖上有太多传言暗示着这个世界越来越被Google所控制,但事实显然不是这样。这个协议是IETF制定的,就跟过去30年间很多其他协议一样。但不得不承认,SPDY是Google非常出色的成果。它不仅仅证明了开发一个新协议的可行性,还充分展现了新协议能带来的好处。 Google公开[声明](http://blog.chromium.org/2015/02/hello-http2-goodbye-spdy-http-is_9.html)了他们会在2016年移除Chrome里对SPDY和NPN的支持,并且极力推动服务器迁移至HTTP/2。 **8.4.2. “这个协议只在浏览器上有用”** 在某种程度上,这是对的。开发http2的一个主要动机就是修复HTTP pipelining。如果在你的应用场景里本来就不需要pipelining,那么确实很有可能http2对你没有太大帮助。虽然这并不是唯一的提升,但显然这是非常重要的一个。 一旦当某些服务意识到在一个连接上建立多路复用流的强大威力时,我认为会有越来越多的程序采用http2。 小规模的REST API和采用HTTP 1.x的简单程序可能不会认为迁移到http2能有多大的优势。但至少http2对绝大部分用户来讲,是几乎没有坏处的。 **8.4.3. “这个协议只对大型网站有用”** 完全不是这样。因为缺乏内容分发网络,小网站的网络延迟往往较高,而多路复用的能力可以极大的改善在高网络延迟下的体验。大型网站往往已经将内容分发到各处,所以速度其实更快。 **8.4.4. “TLS让速度变得更慢”** 这个评价在某种程度上是对的。虽然TLS的握手确实增加了额外的开销,但也有越来越多的方案来减少TLS往返的时间。使用TLS而不是纯文本带来的开销是显著的,有可观证据表明,和传输同样的流量相比,TLS会消耗更多的CPU和其他资源。具体影响有多大以及怎么影响是一个和具体测量有关的课题。更多的例子可以参看[istlsfastyet.com](http://istlsfastyet.com)。 Telecom和一些其他网络服务商,例如ATIS开放网络联盟,表示为了为卫星、飞机等提供的快速网络体验,他们需要一些[不加密的流量](http://www.atis.org/openweballiance/docs/OWAKickoffSlides051414.pdf)来提供caching,压缩和其他技术。 http2并不强制要求使用TLS,所以我们不应该为此担心。 如今,很多互联网使用者已经更希望TLS能被更广泛的使用来保护用户隐私。 实验也证明了通过使用TLS能比用在80端口实现一个新的基于文本的协议更容易成功。因为当前已经有太多中间商使用该方案,所以凡是基于80端口的协议,都很可能被理所当然的当作HTTP 1.1。 最后,得益于http2在单一连接上提供的多路复用流,普通浏览器的正常使用也可以减少TLS握手的次数,所以使用HTTPS仍然会比HTTP 1.1更快。 **8.4.5. “不基于ASCII是没法忍受的”** 虽然当我们可以直接读出协议内容的时候,调试和追踪都会变得更简单。但基于文本的协议更容易产生错误,造成更多解析的问题。 如果你真的无法接受二进制协议,那么你也无法在HTTP 1.x中处理TLS和压缩。而这些技术其实已经被使用了很久了。 **8.4.6. “它根本没有比HTTP/1.1快”** 当然,到底该如何定义和测量“快”就是另外一个话题了,但在SPDY的时代,已经有一些实验证明了该协议会让浏览器载入页面更快(例如华盛顿大学的“[SPDY有多快?](https://www.usenix.org/system/files/conference/nsdi14/nsdi14-paper-wang_xiao_sophia.pdf)”和Hervé Servy的“[评估启用SPDY的Web服务器性能](http://www.neotys.com/blog/performance-of-spdy-enabled-web-servers/)”),同样这些实验也被用来证明http2。我期待能有越来越多的测试实验发布。[httpwatch.com](http://blog.httpwatch.com/2015/01/16/a-simple-performance-comparison-of-https-spdy-and-http2/)也有进行一个简单的测试来证明HTTP/2名副其实。 http2在很多的场景下都证明了自己更快,尤其是在包含非常多资源的高延迟的连接上。而正如之前的章节中提到,目前的趋势就是每个网站包含越来越多的资源和数据。 **8.4.7. “它违反了网络分层”** 你确定这也是反对的理由么?网络分层并不是不可侵犯的。如果我们在制定http2的时候已经踏入了灰色地带,那我们当然可以尝试在限制内制定出更好更高效的协议。 **8.4.8. “它并没有修复很多HTTP/1.1的问题”** 确实是这样。兼容HTTP/1.1的范式是我们的目标之一,所以一些老的HTTP功能仍然被保留。例如一些常用的协议头、可怕的cookies、验证头等等。但保留这些范式的好处就是我们在升级到新协议的时候少掉很多工作,也不需要重写很多底层的东西。Http2其实只是一个新的帧层。 ## 8.5. http2会被广泛部署吗? 现在还言之尚早,但我仍然要在这里做出我的预估。 很多怀疑论者会以“看看IPv6现在的德性”为让我们回想起这个经历了10多年才开始慢慢被采用的协议。但http2毕竟不是IPv6。他是一个建立在TCP之上的使用HTTP更新机制、端口号和TLS等的协议。大部分路由器或者防火墙不需要为此而进行更改。 Google向世界展示了他们的SPDY,证明了像这样的新协议也能在足够短的时间内拥有多种实现,并且能被浏览器和服务所采用。虽然如今支持SPDY服务器端数量在1%以内,但通过这些服务器所交换的数据却要大很多。很多非常流行的网站现在也有提供SPDY支持。 我认为建立在SPDY的基本范式之上的http2会被更广泛的部署,毕竟它是IETF制定的协议。而SPDY因为背负了“它是Google的协议”这个恶名,导致它的发展总是畏首畏脚。 在它首次发布的幕后有很多大型浏览器支持。来自Freifox,Chrome和IE的代表宣布了他们会发布支持http2特性的浏览器,并且他们已经演示了一些能正常运作的实现。 也有很多像Google,Twitter和Facebook这样的大公司希望尽快支持http2,所以我们可以期待着很快能有支持http2的服务器(例如Apache HTTP Server和nginx)。[H2o](https://github.com/h2o/h2o)作为一个极有潜力的新生HTTP服务器,也同样支持http2。 那些大型代理程序开发者,例如HAProxy、Squid和Varnish也表示出了他们对支持http2的兴趣。 我也相信一旦规范被RFC批准,会有更多的实现雨后春笋般的涌现出来。 在2015年1月下旬,默认启用HTTP/2的Firefox 35发布后,Google也宣布Chrome 40对2%的用户启用了该功能。虽然他没有告诉我们具体的数字,但HTTP/2已经差不多占到了他们全球流量的5%。与此同时,Firefox 35记录到了9%的相应都是HTTP/2。
';

扩展

最后更新于:2022-04-01 20:52:34

# 7. 扩展 协议强制规定接收方必须读取并忽略掉所有未知帧类型的帧。双方必须在逐跳原则(hop-by-hop basis)基础上协商使用新的帧,这些帧的状态无法被改变,并且也不受流控制。 是否应该允许添加扩展的这个话题在制定http2协议的时候被反复讨论了很久。在draft-12之后,最终确定允许添加扩展。 但扩展不再是协议本身的一部分,它被记录在核心协议规范之外。到目前为止,有两种曾被http2工作组包含在协议里的帧,很可能率先被纳入协议的扩展部分。这两个曾被当作“原生”的帧非常流行,所以接下来我会详细讨论它们。 ## 7.1. 备选服务(Alternative Services) 随着http2逐渐被接受,我们有理由猜测,相对于HTTP 1.x,TCP连接会更长且被保持的更久。对客户端来讲,最好是到每个主机/站点的每一条连接都可以做尽可能多的事情,这也需要每个连接保持开启更长的时间。 但这会影响到HTTP负载均衡器的正常工作,比如在一个网站想建议客户端连接到另外一个主机的时候。通常,网站此举的目的在照顾性能,但也可能是正常维护或类似原因。 服务器将会通过发送Alt-Svc头(或者http2的ALTSVC帧)来告知客户端另一个备选服务。即另外一条指向不同的服务源、主机或端口,但却能获取同样内容的路由。 客户端可以尝试异步的连接到该服务,或者可用的话就选择备选方案。 **7.1.1. 机会型TLS(Opportunistic TLS)** Alt-Svc头部允许服务器通过`http://`告诉客户端:同样的内容也可以通过TLS连接来获取。 这是个还在讨论中的功能。这样的连接会导致未认证的TLS,并且在任何地方也不会被广播为“安全”,同时不会在客户端界面上出现任何锁标识,所以没法让用户知道这其实不是常规的HTTP连接。这就是很多人强烈反对机会型TLS的原因。 ## 7.2. 阻塞(Blocked) 当有数据需要被发送,但流控制却禁止发送任何数据时,此类型的帧将会被发送**仅**一次。这种帧设计的目的在于,如果你接收到了此帧,那么连接中必然有错误发生或者是得到了低于期望的传输速度。 在此帧被放到协议扩展部分之前,draft-12中的一段话: > 阻塞帧被包含在此版本的草案中作为实验,如果没有得到良好的反馈,就把它删除。
';

http2协议

最后更新于:2022-04-01 20:52:32

# 6. http2协议 背景介绍就到此为止了,历史的脚步将我们推到了今天这一步。现在让我们深入看看该协议的规范,看看那些细节和概念。 ## 6.1. 二进制 http2是一个二进制协议。 仔细想想,如果你是一个曾经跟互联网协议打过交道,那你很可能本能反对二进制协议,你甚至准备好了一大堆理由来证明基于文本/ascii的协议是多么的有用,正如你曾无数次地通过手工输入HTTP请求来通过telnet远程登陆。 二进制的http2可以使成帧更便捷。在HTTP1.1和其他基于文本的协议中,识别帧的起始和结束相当复杂。而在移除掉可选的空白符和其他冗余后,实现这些会变得更容易。 另一方面,从帧结构中分离出协议本身的部分也变得更容易。而在HTTP1中,各个部分相互交织,一团乱麻。 协议的压缩特点和其经常运行在TLS之上的事实让纯文本的属性值变得毫无作用,毕竟也无法从数据流上看到文本。我们需要习惯于使用类似Wireshark的工具来从协议层面对http2一探究竟。 调试这样的协议将需要curl这样的工具,要进一步地分析网络数据流需要类似Wireshark的http2解析器。 ## 6.2. 二进制格式 http2发送二进制帧。帧的类型有很多种,但他们都有如下的公共字段: Type, Length, Flags, Steam Identifier和frame payload ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-08-09_55c75bc1d0f63.png) http2的规范一共定义了10种不同的帧,其中最基础的两种分别对应于HTTP 1.1的DATA和HEADERS。之后我会更详细的介绍其中一些帧。 ## 6.3. 多路复用的流 上一节提到的Stream Identifier定义了二进制帧的格式,http2连接上传输的每个帧都关联到一个“流”。流是一个逻辑上的联合,一个独立的,双向的帧序列。这一系列帧在客户端和服务器中通过http2连接进行交换。 每个单独的http2连接都可以包含多个并发的流,这些流中交错的包含着来自两端的帧。流既可以被客户端/服务器端单方面的建立和使用,也可以被双方共享,或者被任意一边关闭。在流里面,每一帧发送的顺序非常关键。接收方会按照收到帧的顺序来进行处理。 流的多路复用意味着在同一连接中来自各个流的数据包被混合在一起。两个(或者更多)独立的“数据列车”被拼凑到了一辆列车上,最终在终点站被分开。下图就是两列“数据火车”的示例 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-08-09_55c75bc1e45d9.png) 它们就是这样通过多路复用的方式被组装到了同一列火车上。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-08-09_55c75bc2174c2.png) 在http2里面,我们很容易可以看到10个甚至100个同时并存的流。创建一个新的流的代价也非常低。 ## 6.4. 优先级和依赖性 每个流都包含一个优先级,优先级被用来告诉对端哪个流更重要。 优先级的工作机制在协议中被改变多次,至今仍在讨论。重点在于要让客户端能指定哪个流更重要,并且提供一个依赖参数来指定流的依赖关系。 优先级能动态的被改变。这样当用户滚动一个全是图片的页面的时候,浏览器能够指定哪个图片有更高的优先级。或者是在你切换标签页的时候,浏览器可以提升新切换到页面所包含流的优先级。 ## 6.5. 头压缩 HTTP是无状态协议。简而言之,这意味着每个请求必须要携带服务器需要的所有细节,而不是让服务器保存住之前请求的元数据。因为http2没有改变这个范式,所以它也需要这样(携带所有细节)。 这也保证了HTTP可重复性。当一个客户端从同一服务器请求一些资源(例如页面的图片)的时候,这些请求看起来几乎是一致的。而这些大量一致的东西正好值得被压缩。 当每个页面资源的个数上升的时候,cookies和请求的大小都会增加,而每个请求都会包含的cookie几乎是一模一样的。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-08-09_55c75bc23b50c.png) HTTP 1.1请求的大小变得越来越大,有时甚至会大于TCP窗口的初始大小,这会严重拖累发送请求的速度。因为它们需要等待带着ACK的响应回来以后,才能继续被发送。这也是需要压缩的理由。 **6.5.1. 压缩是非常棘手的课题** HTTPS和SPDY的压缩机制被发现有受[BREACH](http://en.wikipedia.org/wiki/BREACH_%28security_exploit%29)和[CRIME](http://en.wikipedia.org/wiki/CRIME)攻击的隐患。通过向流中注入一些已知的文本来观察输出的变化,攻击者可以推出原始发送的数据。 为协议的动态内容进行压缩并使其免于被攻击,需要仔细且全面的考虑。而这正是HTTPbis小组尝试去做的。 [HPACK](http://www.rfc-editor.org/rfc/rfc7541.txt),_HTTP/2头部压缩_,顾名思义它是一个专为http2头部设计的压缩格式。确切的讲,它甚至被制定写入在另外一个单独的草案里。新的格式同时引入了一些其他对策让破解压缩变得困难,例如采用帧的可选填充和用一个bit作为标记,来让中间人不压缩指定的头部。 用Roberto Peon(HPACK的设计者之一)的话说,“HPACK旨在提供一个一致性的实现使信息量的损失尽可能少,使编解码快速而方便,使接收方能控制压缩文本的大小,允许代理重新建立索引(如,通过代理在前后端共享状态),以及对哈夫曼编码串的更快速比较”。 ## 6.6. 重置 - 后悔药 HTTP 1.1的有一个缺点是:当一个含有确切值的Content-Length的HTTP消息被送出之后,你就很难中断它了。当然,通常你可以断开整个TCP链接(但也不总是可以这样),但这样导致的代价就是需要重新通过三次握手建立一个新的TCP连接。 一个更好的方案是只终止当前传输的消息并重新发送一个新的。在http2里面,我们可以通过发送RST_STREAM帧来实现这种需求,从而避免浪费带宽和中断已有的连接。 ## 6.7. 服务器推送 这个功能通常被称作“缓存推送”。主要的思想是:当一个客户端请求资源X,而服务器知道它很可能也需要资源Z的情况下,服务器可以在客户端发送请求前,主动将资源Z推送给客户端。这个功能帮助客户端将Z放进缓存以备将来之需。 服务器推送需要客户端显式的允许服务器提供该功能。但即使如此,客户端依然能自主选择是否需要中断该推送的流。如果不需要的话,客户端可以通过发送一个RST_STREAM帧来中止。 ## 6.8. 流量控制 http2上面每个流都拥有自己的公示的流量窗口,它可以限制另一端发送数据。如果你正好知道SSH的工作原理的话,这两者非常相似。 对于每个流来说,两端都必须告诉对方自己还有更多的空间来接受新的数据,而在该窗口被扩大前,另一端只被允许发送这么多数据。只有数据帧受流量控制。
';

http2的观念

最后更新于:2022-04-01 20:52:29

# 5. http2的基本概念 http2到底做了些什么呢?到多远才是HTTPbis小组工作的界限? 事实上,http2的界定非常严格,让小组的工作颇为掣肘。 - [X] 它必须维持HTTP的范式。毕竟它只是一个让客户端发送请求到服务器的基于TCP的协议。 - [X] 不能改变`http://`和`https://`这样的URL,也不能对其添加新的结构。使用这类URL的网站太多了,没法指望他们全部改变。 - [X] HTTP1的服务器和客户端依然会存在很久,所以我们必须提供HTTP1到http2服务器的代理。 - [X] 随后,我们也要让这种代理能够将http2的功能一对一的映射到HTTP 1.1的客户端。 - [X] 删除或者减少协议里面那些可选的部分。虽然这并不是一个大的需求,但是SPDY和Google的团队会非常喜欢这点。让协议里所有部分都成为强制要求的,就能防止人们在实现的时候偷懒,从而避免将来的问题。 - [X] 不再使用小版本号。服务器和客户端都必须确定自己是否完整兼容http2或者彻底不兼容。如果将来该协议需要被扩充更变,那么新的协议将会是http3,而不是http 2.x。 ## 5.1. http2和现有的URI结构 如前所述,现有的URI结构正在被HTTP 1.x使用而不能改变,所以http2也必须沿用该结构。正因如此我们才必须找到一种方式将协议升级至http2,或者让服务器使用http2来彻底替代旧的协议。 HTTP 1.1本身就有制定“升级”的方案:提供一个头,让服务器在收到旧协议请求的时候,向客户端发送新协议的响应。这样做的代价是需要一次往返通信。 这个往返通信的代价是SPDY团队不能接受的。因为他们只实现了基于TLS的SPDY,所以他们也只开发了一个TLS的扩展来简化协议的协商。这个扩展被称作NPN(Next Protocol Negotiation),通过它,服务器通知客户端所有他支持的协议,从而让客户端从中选择一个合适的。 ## 5.2. 为`https://`所准备的http2 足够的关注使得http2在TLS上得以正常运作,SPDY只支持TLS,所以按理说TLS也应成为http2 必需的组件,但出乎意料的是http2仅将TLS作为可选部分。然而,全球两大浏览器领导者 - Firefox和Chrome明确地表示,他们只实现基于TLS的http2. 只选择TLS的原因包括了保护用户隐私,早期的评估结果表明,将新的协议建立在TLS上更可能成功。这也是因为所有来自80端口的流量都会被当作HTTP 1.1或者是其某个变种,而不是另外一个种全新的协议。 关于是否该强制使用TLS的主题在邮件组和会议上引起了不小的争议 - 这到底是好是坏呢?不管怎么样,对于这种备受争议的话题请谨慎讨论,尤其是当你面对一个HTTPbis小组成员的时候。 类似地,还有一个激烈而长期的辩论,即当使用TLS时http2是否应该强制规定密码列表,或者应该建立一个黑名单,或者它根本就不需要从TLS层得到任何东西,而由TLS工作组来解决。最后规范指定TLS最低版本是1.2,并且有加密组的限制。 ## 5.3 基于TLS之上的http2协商 Next Protocol Negotiation (NPN)是一个用来在TLS服务器上协商SPDY的协议。IETF将这个非正式标准进行规范,从而变成了ALPN(Application Layer Protocol Negotiation)。ALPN被推广用于http2,而SPDY客户端和服务器仍然使用NPN。 由于NPN先诞生,而ALPN还经历了一些标准化过程。所以许多早期的http2客户端和服务器在协商http2时同时实现了这两者的扩展。并且,由于SPDY使用NPN,不少服务器同时提供SPDY和http2来支持NPN和APLN。 ALPN和NPN的主要区别在于谁持有会话协议的决定权,ALPN是由客户端给服务器发送一个协议优先级列表,由服务器最终选择一个合适的。而NPN则正好相反,是客户端有最终决定权。 ## 5.4 为`http://`所准备的http2 如前所述,对于纯文本的HTTP1.1来说,协商http2的方法就是给服务器发送一个带**升级**头部的报文。如果服务器支持http2,它将回复“101 Switching”状态码,并从此开始在该连接上使用http2。也许你很容易就发现这个升级流程会造成一个完整的往返时延开销,但好处是http2连接相比HTTP1可以被更大限度地重用和保持。 虽然有些浏览器厂商的发言人宣称他们不会实现这种http2会话方式,但IE团队已公开表示他们会实现,与此同时,curl已经支持该方式。
';

升级HTTP

最后更新于:2022-04-01 20:52:27

# 4. 升级HTTP 花点功夫去改善HTTP协议显然是极好的事情。我们可以着手于以下几个方面: 1. 降低协议对延迟的敏感 1. 修复pipelining和head of line blocking的问题 1. 防止主机需求更高的连接数量 1. 保留所有现有的接口,内容,URI格式和结构 1. 由IETF的HTTPbis工作组来制定 ## 4.1. IETF和HTTPbis工作组 The Internet Engineering Task Force (IETF)是一个开发和推广互联网标准的组织。他们的重心是在协议层面。他们最出名的工作是制定了TCP、DNS、FTP和它们最佳实践的RFC规范,但HTTP和许多其他协议却进展缓慢。 IETF成立独立的“工作组”以便完成某一特定领域内的目标,他们建立一个“章程”用以制定达到目标的指导方针和规范。在这里,任何人都可以参与讨论和开发,并且每个人有同等的话语权,没人关心你来自哪个公司或组织。 HTTPbis工作组(我们待会儿再解释这个名字)在2007年夏天成立之后就着手于HTTP1.1标准的更新。在组内,关于下一版本HTTP协议的讨论实际上在2012年后期才开始。而HTTP1.1的更新工作在2014年初完成,并被整理成RFC7320系列。 2014年6月初,HTTPbis工作组名义上的最终版文档大会在纽约召开。剩下的讨论以及等IETF走完流程通过官方的RFC版本预计在来年完成。 一些HTTP领域的权威缺席了工作组的讨论和会议。我并不想在此提及任何公司和产品。但事实上当今互联网上很多声音仿佛也在肯定,不需要这些公司参与IETF也能做得很好。。。 ## 4.1.1. 名字中的“bis” 工作组名字中的“bis”来自拉丁语中表示[“二”](http://en.wiktionary.org/wiki/bis#Latin)的副词,Bis通常被IETF用作名字的后缀来以表示标准的升级或者一些二次工作,比如这里是针对HTTP1.1。 ## 4.2. 起源于SPDY的http2 [SPDY](http://en.wikipedia.org/wiki/SPDY)是由Google牵头开发的协议。他们将其开源,使得每个人都可以参与开发。但很明显,他们通过控制浏览器的实现和享用着优质服务的大量用户来获益。 当HTTPbis小组决定开始制定http2的时候,SPDY已经充分证实了它是一个非常好用的方案。当时已经有人在互联网上成功部署SPDY,并且也有一些文章讨论他的性能。因此,http2便基于SPDY/3草案进行一些修改之后发布了http2的draft-00。
';

那些年,克服延迟之道

最后更新于:2022-04-01 20:52:25

# 3. 那些年,克服延迟之道 再困难的问题也有解决的方案,但这些方案却良莠不齐。 ## 3.1. Spriting Spriting是一种将很多较小的图片合并成一张大图,再用JavaScript或者CSS将小图重新“切割”出来的技术。 网站可以用该技术来提速:在HTTP 1.1里,下载一张大图比下载100张小图快得多。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-08-09_55c75bc173aaf.png) 但是当某些页面只需要显示其中几张小图时,这种方案的缺点就凸显出来了:它必须将整张大图都从cache里取出,而不能将最频繁使用的那些图片保留在cache里。 ## 3.2. 内联(Inlining) 内联是另外一种防止发送很多小图请求的技巧,它将图片的原始数据嵌入在CSS文件里面的URL里。而这种方案的优缺点跟Spriting很类似。 ~~~ .icon1 { background: url(data:image/png;base64,) no-repeat; } .icon2 { background: url(data:image/png;base64,) no-repeat; } ~~~ ## 3.3. 拼接(Concatenation) 大型网站往往会包含大量的JavaScript文件。一些前端工具能帮助开发人员将这些文件合并为一个大的文件,从而让浏览器能通过一个请求下载完,而不是发无数请求来分别下载那些小的JavaScript。但如果某页面只需要其中一小部分代码,它也必须下载完整的那份。而一个小小的文件改动也会造成大量数据的重载。 这种手段也给开发者造成了很大的不便。 ## 3.4 分片(Sharding) 最后一个我要说的性能优化技术叫做分片。顾名思义,分片就是把你的服务分散在尽可能多的主机上。这种方案乍一听比较奇怪,但是实际上在它背后却有非常深刻的道理! 最初的HTTP 1.1规范提到一个客户端最多只能对同一主机建立两个TCP连接。因此,为了不和规范冲突,一些聪明的网站使用了新的主机名。这样的话,用户就能和网站建立更多的连接,从而降低载入时间。 后来,两个连接的限制被取消了,现在的客户端可以轻松地和每个主机建立6-8个连接。但连接的上限却是依然存在的,所以网站依然会用这种技术来提升连接的数量。随着资源个数的提升(上面章节的图例),网站需要更多的连接来保证HTTP协议的效率,从而提升载入速度。在现今的网站上,使用50甚至100个连接来打开一个页面并不罕见。[httparchive.org](http://httparchive.org)的最新记录显示,在Top 30万个URL中平均使用38(!)个TCP连接来显示页面。并且这个数字仍然在缓慢的增长。 另外一个将图片或者其他资源分发到不同主机的理由是可以不使用cookies,毕竟现今cookies的大小已经非常可观了。无cookies的图片服务器意味着更小的HTTP请求和更好的性能! 下面的图片展示了访问一个瑞典著名网站的时候的数据包,请注意这些请求是如何被分发到不同主机的。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-08-09_55c75bc18a3e9.png)
';

HTTP的现状

最后更新于:2022-04-01 20:52:23

# 2. HTTP的现状 互联网上几乎所有内容都采用HTTP 1.1作为通信协议。人们在该协议上投入了大量精力,基于它的基础架构也因此日臻完善。正因如此,在HTTP协议之上构建新的方案会比从底层建立新的协议容易得多。 ## 2.1. HTTP 1.1过于庞大 HTTP刚诞生的时候只被当作是一个相对简单直观的协议,但时间证明这种初始设计并不如意。定义HTTP 1.0规范的RFC 1945共有60页,发布于1996年。仅仅3年之后,定义HTTP 1.1规范的RFC 2616却一下增长到了176页。然而,当我们在IETF在进行该规范更新工作时,它被拆分成了总页数更多的六个文档(这就是RFC 7230及其文件族的诞生)。不管怎么样,HTTP 1.1包含了太多细节和可选的部分,这让它变得过于庞大。 ## 2.2. 过多的可选项 HTTP 1.1不仅包含了非常多的细枝末节,还为将来的扩展预留的很多选项。这种事无巨细的风格导致在现在的软件生态中,几乎没有任何实现真正实现了协议中提及的所有细节,甚至要弄清楚“所有细节”到底包括哪些细节都非常困难。正因为如此,很多最初不常用的功能在后来的实现中很少会被支持,而有些最初实现了的功能,却又很少被使用。 随着时间推移,这些当初看似被边缘化的功能逐渐被用上,客户端和服务器的互用性(interoperability)问题就被暴露了出来。HTTP管线化(HTTP Pipelining)就是一个非常好的例子。 ## 2.3. 未能被充分利用的TCP HTTP 1.1很难榨干TCP协议所能提供的所有性能。HTTP客户端和浏览器必须要另辟蹊径的去找到新的解决方案来降低页面载入时间。 与此同时,人们也尝试去用新的协议来替代TCP,但结果证明这也非常困难。无奈之下,我们只能尝试同时改进TCP协议本身和基于TCP的上层协议。 简言之,我们也能通过更好的利用TCP来减少传输过程中的暂停,并充分挖掘利用那些本可以用于发送/接受更多数据的时间。下面几段将会着重讨论这些问题。 ## 2.4. 传输大小和资源数量 如果仔细观察打开那些最流行的网站首页所需要下载的资源的话,会发现一个非常明显的趋势。 近年来加载网站首页需要的下载的数据量在逐渐增加,并已经超过了1.9MB。但在这里我们更需要关注的是:显示每个页面所需下载的平均资源数也超过了100个。 正如下图所示,这种趋势已经持续了很长一段时间,并却没有减缓的迹象。该图表中绿色直线展示了传输数据大小的增长,红色直线展示了平均请求资源数量的增长。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-08-09_55c75bc146f5b.png) ## 2.5 恼人的延迟 HTTP 1.1对网络延迟非常敏感。部分原因是HTTP Pipelining还有很多问题,所以对大部分用户来说是默认关闭的。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-08-09_55c75bc152442.png) 虽然近几年来网络带宽增长非常快,但是与此相对的是,我们并没有看到网络延迟有对应程度的降低。在高延迟的网络上(比如移动设备),即使拥有高连接速率,也很难获得优质快速的网络体验。 另外一个需要低延迟的场景是某些视频服务,如视频会议、游戏和一些类似无法预生成待发送数据流的服务。 ## 2.6 线头阻塞(Head of line blocking) HTTP Pipelining是这样一种技术:在等待上一个请求响应的同时,发送下一个请求。(译者注:作者这个解释并不完全正确,HTTP Pipelining其实是把多个HTTP请求放到一个TCP连接中一一发送,而在发送过程中不需要等待服务器对前一个请求的响应;只不过,客户端还是要按照发送请求的顺序来接收响应。)但就像在超市收银台或者银行柜台排队时一样,你并不知道前面的顾客是干脆利索的还是会跟收银员/柜员磨蹭到世界末日(译者注:不管怎么说,服务器(即收银员/柜员)是要**按照顺序**处理请求的,如果前一个请求非常耗时(顾客磨蹭),那么后续请求都会受到影响),这就是所谓的线头阻塞(Head of line blocking)。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-08-09_55c75bc15f7a6.png) 当然,你可以在选择队伍时候就做好功课,去排一个你认为最快的队伍,或者甚至另起一个新的队伍(译者注:即新建一个TCP连接)。但不管怎么样,你总归得先选择一个队伍,而且一旦选定之后,就不能更换队伍。 但是,另起新队伍会导致资源耗费和性能损失(译者注:新建 TCP 连接的开销非常大)。这种另起新队伍的方式只在新队伍数量很少的情况下有作用,因此它并不具备可扩展性。(译者注:这段话意思是说,靠大量新建连接是不能有效解决延迟问题的,即HTTP Pipelining并不能彻底解决Head of line blocking问题。)所以针对此问题并没有完美的解决方案。 即使在2015年的今天,大部分桌面浏览器也默认关闭了HTTP pipelining功能。 关于这个问题的更多细节,可以参阅Firefox的 [bugzilla #264354](https://bugzilla.mozilla.org/show_bug.cgi?id=264354)。
';

背景

最后更新于:2022-04-01 20:52:20

# 1. 背景 这篇文档会从技术和协议层面介绍http2。文档起源于2014年4月我在斯德哥尔摩做了一次相关的演讲,在那之后我对演讲内容的细节进行了一些解释和补充,从而写出了这篇文档。 正式版http2规格标准叫做RFC 7540,发布于2015年5月15日:[http://www.rfc-editor.org/rfc/rfc7540.txt](http://www.rfc-editor.org/rfc/rfc7540.txt) 如果你有在这篇文章中发现任何我的失误造成的错误或疏漏,请帮我指正。我会在后续版本中修改。 为了让阅读体验更流畅,在这篇文章中我会使用“http2”来指代这一新协议,但请记住该协议的正式名字是HTTP/2。 _这篇文档版本为1.12,发布于2015年5月21日。_ ## 1.1. 关于作者 我的名字叫做Daniel Stenberg,在Mozilla工作。在过去20年,我一直致力于开源事业,参与了多个网络方面的项目。可能我最广为人知的身份是curl和libcurl的首席开发者。同时,我也参与了IETF HTTPbis工作组多年,工作在HTTP 1.1和http2标准化的一线. - Email: daniel@haxx.se - Twitter: [@bagder](https://twitter.com/bagder) - Web: [daniel.haxx.se](http://daniel.haxx.se/) - Blog: [daniel.haxx.se/blog](http://daniel.haxx.se/blog/) ## 1.2. 帮助我! 如果你在该文档里面发现任何错误、疏漏,请发送给我一份相关段落更改后的版本,我会进行修正并且注明所有对文档有贡献的人!希望这份文档能越来越好。 这篇文档可以在[http://daniel.haxx.se/http2](http://daniel.haxx.se/http2)下载。 ## 1.3. 许可证 这篇文档基于Createive Commons Attribution 4.0发布: [http://creativecommons.org/licenses/by/4.0/](http://creativecommons.org/licenses/by/4.0/) ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-08-09_55c75bc13669c.png) ## 1.4. 文档历史 该文档的第一版发布于2014年4月25日。下面是最近主要改动的更新历史。 **Version 1.12:** - 1.1: HTTP/2 is now in an official RFC - 6.5.1: link to the HPACK RFC - 9.1: mention the Firefox 36+ config switch for http2 - 12.1: Added section about QUIC **Version 1.11:** - Lots of language improvements mostly pointed out by friendly contributors - 8.3.1: mention nginx and Apache httpd specific acitivities **Version 1.10:** - 1: the protocol has been “okayed” - 4.1: refreshed the wording since 2014 is last year - front: added image and call it “http2 explained” there, fied link - 1.4: added document history section - many spelling and grammar mistakes corrected - 14: added thanks to bug reporters - 2.4: (better) labels for the HTTP growth graph - 6.3: corrected the wagon order in the multiplexed train - 6.5.1: HPACK draft-12 **Version 1.9: February 11, 2015** - Updated to HTTP/2 draft-17 and HPACK draft-11 - Added section "10. http2 in Chromium" (== one page longer now) - Lots of spell fies - At 30 implementations now - 8.5: added some current usage numbers - 8.3: mention internet explorer too - 8.3.1 "missing implementations" added - 8.4.3: mention that TLS also increases success rate **Version 1.8: January 15th, 2015** - Compressed the images better, leading to a much smaller PDF - Updated to draft-16 and hpack-10 - Replaced several images - Linkifid many URLs - Added a few questions in 8.4 - Mentions IETF Last Call
';

简介

最后更新于:2022-04-01 20:52:18

> **Notice:** This is the Simplified Chinese translation of _[http2 explained](http://daniel.haxx.se/http2/)_ . Thank [Daniel Stenberg](http://daniel.haxx.se/) for his great work! # 简介 《http2讲解》这篇文档会从技术和协议层面介绍HTTP/2协议,主要内容包括HTTP/2协议产生的背景、协议本身、实现和未来。原作者为[Daniel Stenberg](http://daniel.haxx.se/)。 阅读请访问: - [中文版](https://www.gitbook.com/book/ye11ow/http2-explained/details) - [英文原版](http://daniel.haxx.se/http2/) # 翻译进度 正在进行第二遍review,对应英文原始版本1.12。我会用注释形式标记出翻译的不太好地方,如果有童鞋想来帮忙的话,请提PR或者邮件我。 **目前第五章和第八章需要深度校对!** # 主要翻译者 - Calvin Zhang - Simon Xia - [其他贡献者](https://github.com/ye11ow/http2-explained-chinese/graphs/contributors)
';