https://www.infoq.cn/article/IgME_4ebP3d46m3tHbaT
HTTP 协议为 Web 的发展提供了驱动力,它始于 1991 年的 HTTP/0.9,在 1999 年演变为 HTTP/1.1,并由 IETF(互联网工程任务组)负责进行标准化。HTTP/1.1 存在了很长一段时间,但 Web 不断变化的需求要求推出更好的协议,于是 HTTP/2 在 2015 年出现了。IETF 最近宣布要推出新的版本,即 HTTP/3。对于有些人来说,这是一个惊喜,但也会让他们感到有一点点困惑。如果你没有密切关注 IETF 的工作,就会觉得 HTTP/3 出现得很突然。不过,我们可以通过一系列实验和 Web 协议的演变史来追溯它的起源,特别是 QUIC 传输协议。
如果你还不熟悉 QUIC,可以先看看我的一些同事所写的文章。John 的这篇文章描述了当今 HTTP 世界的一些恼人之处,Alessandro 的这篇文章描述了传输层的实际细节,而 Nick 的这篇文章介绍了如何进行测试。我们在https://cloudflare-quic.com收集了更多的资源。如果你喜欢,请务必看一看我们用 Rust 实现的 QUIC 协议quiche。
HTTP/3 是 HTTP 应用程序到 QUIC 传输层的映射。这个名称在第 17 版草案(draft-ietf-quic-http-17)中正式启用,该草案于 2018 年 10 月底提出,在 11 月于曼谷举行的 IETF 103 大会期间进行了讨论并达成初步的共识。HTTP/3 之前叫作 HTTP over QUIC,再往前又叫 HTTP/2 over QUIC。在那之前,我们有 HTTP/2 over gQUIC,再往前,我们有 SPDY over gQUIC。事实上,HTTP/3 只是一种基于 QUIC(基于 UDP 的多路复用和安全传输)的 HTTP 新语法。
在这篇文章中,我们将探讨 HTTP/3 旧名称背后的历史以及改名背后的动机。我们将回到 HTTP 的早期阶段,介绍一路走来所做的工作。如果你想要获得一个整体的视图,可以打开这个非常详细的SVG 版本。
HTTP/3 协议层
场景设定
在开始介绍 HTTP 之前,需要注意的是,有两个协议都使用了 QUIC 这个名称。gQUIC 通常用来表示谷歌 QUIC(原始协议),而 QUIC 通常用来表示 IETF 正在进行标准化的版本。
从 90 年代初期开始,Web 的需求已经发生了很大的变化。我们有了新版本的 HTTP,并增加了传输层安全(TLS)来增强安全性。
为了更好地解释 HTTP 和 TLS 的历史,我整理了协议规范和日期的细节。这些信息通常以文本形式呈现出来,例如按日期排序的项目列表。但因为存在标准分支,它们在时间上有所重叠,简单的列表无法表达出这种复杂的关系。而且,在 HTTP 方面还存在一些并行的工作,这些工作通过重构核心协议来简化使用,通过扩展协议来增加新的用途,以及通过重新定义数据交换方式来提高性能。要想跨越近 30 年的互联网发展史和不同的工作流分支,并把它们串起来,需要对它们进行可视化。于是,我制作了 Cloudflare Secure Web Timeline。
接下来,我将按照这个时间表来解释 HTTP 历史的关键篇章。为了更好地理解本文的内容,最好先知道为什么要进行协议标准化以及 IETF 是如何实现的。因此,在回到时间表之前,我们先简要介绍这个主题。如果你已经很熟悉 IETF,可以跳过下面的部分。
互联网标准的类型
通常,标准定义了共同的引用术语、范围、约束、适用性和其他考虑事项。标准可以以多种形式存在,可以是非正式的(也就是所谓的“事实上的标准”)或正式的(由标准定义组织——例如 IETF、ISO 或 MPEG——同意或发布)。标准被用在很多领域,甚至连茶叶都有一个正式的标准——英国制茶标准 BS 6008。
早期 Web 使用的是在 IETF 外部发布的 HTTP 和 SSL 协议,这些在 Secure Web Timeline 上被标记为红线。客户端和服务器对这些协议的采用使它们成为事实上的标准。
到了某个时刻,人们决定将这些协议正式化(后面部分将描述其背后的动机)。互联网标准通常由 IETF 负责定义,IETF 的指导原则是“粗略共识和可运行的代码”。这个原则以互联网的开发和部署经验为基础,与尝试在真空中开发完美方案的“clean room”方法是不一样的。
IETF 互联网标准被称为 RFC。这个解释起来很复杂,所以我建议你阅读由 QUIC 工作组联合主席 Mark Nottingham 撰写的博文“如何阅读 RFC”。这里所谓的工作组(或 WG)一般是指邮件列表。
IETF 每年都会召开三次会议,为所有工作组提供时间和设施,如果他们愿意,可以亲自参加会议。会议期间的议程可能安排得非常紧凑,只有非常有限的时间可用于深入讨论技术领域的问题。为了解决这个问题,一些工作组还选择在 IETF 常规会议中间的几个月召开临时会议。自 2017 年以来,QUIC 工作组已经召开了几次临时会议,会议主页上提供了完整的会议清单。
IETF 会议还为其他与 IETF 相关的人员提供了会面的机会,例如互联网架构委员会(Internet Architecture Board)或互联网研究工作组(Internet Research Task Force)。近年来,在 IETF 会议之前的周末都会举行 IETF Hackathon。这为社区提供了开发可运行代码的机会,更重要的是,可以与其他人在同一个房间里进行互操作性测试,这样有助于找出规范中存在的问题。
本文要强调的一点是,RFC 不是突然间出现的,它们一般会经历一个过程,通常从 IETF 互联网草案(I-D)开始。如果规范已经存在,那么要准备一个 I-D 就很简单,只需要进行简单的重新格式化。I-D 从发布之日起有 6 个月的有效期。要保持 I-D 的活跃状态,就要发布新版本。在实际当中,一个 I-D 的消失并不会产生多大后果,而且这种事情经常发生。这些文件会继续托管在IETF 文档网站上,任何想要阅读它们的人都可以继续访问它们。
I-D 在 Secure Web Timeline 中使用紫色线条表示。每条线都有一个唯一的名称,格式为 draft-{作者姓名}-{工作组}-{主题}-{版本}。工作组字段是可选的,有时会发生变化。如果一个 I-D 被 IETF 采纳,或者直接由 IETF 内部发起,名字则为 draft-ietf-{工作组}-{主题}-{版本}。I-D 可能会有分支,会发生合并,或者分支直接停止发展。版本从 00 开始,每次发布新草案时增加 1。例如,I-D 第 4 稿的版本为 03。如果 I-D 名称发生变化,版本将重置为 00。
需要注意的是,任何人都可以向 IETF 提交 I-D,但你不应该把它们当作标准来看待。如果 IETF 的标准化流程针对某个 I-D 达成了共识,并且最终文档通过了评审,我们最终会得到一个 RFC。在这个阶段名称会再次发生变化。每个 RFC 都会获得一个唯一的编号,例如 RFC 7230。这些在 Secure Web Timeline 上使用蓝线表示。
RFC 是不可变文档,这意味着修改 RFC 后需要一个全新的编号。修改 RFC 可能是为了合并勘误(编辑方面或技术方面的错误)或为了改进规范的布局。RFC 可能会淘汰旧版本(完全替换),或者更新它们(实质性变更)。
所有 IETF 文档均可在http://tools.ietf.org上公开获得。我个人认为IETF Datatracker对用户更加友好,因为它提供了文档的进度可视化。
下面是一个例子,显示了 RFC 1945(HTTP/1.0)的开发过程,很显然,它是 Secure Web Timeline 的灵感来源。
有趣的是,在我创建 Secure Web Timeline 的过程中,我发现上面的可视化其实是不对的。由于某种原因,它缺少了 draft-ietf-http-v10-spec-05。由于 I-D 的生命周期是 6 个月,因此在成为 RFC 之前似乎存在一个空白,实际上,草案 05 在 1996 年 8 月之前仍然有效。
Secure Web Timeline
在稍微了解了互联网标准文档的实现方式之后,现在可以开始介绍 Secure Web Timeline 了。接下来将展示一些图表,它们显示了整个时间表的重要部分。每个点代表文档或功能的可用日期。对于 IETF 文档,为清晰起见,省略了草案编号。如果你想查看所有详细信息,请参看完整的时间表。
HTTP 从 1991 年的 HTTP/0.9 协议开始,在 1994 年发布了 draft-fielding-http-spec-00,这个 I-D 很快被 IETF 采用,改名为 draft-ietf-http-v10-spec-00。这个 I-D 在 1996 年成为 RFC 1945(HTTP/1.0)之前经历了 6 个草案版本。
但是,在 HTTP/1.0 相关工作完成之前,另一项与 HTTP/1.1 相关的工作就已启动。draft-ietf-http-v11-spec-00 于 1995 年 11 月发布,并于 1997 年正式作为 RFC 2068。你们可能已经发现 Secure Web Timeline 中并未完全捕获这一系列事件,这是可视化工具的问题。
1997 年中期,HTTP/1.1 的修订工作启动了,对应的 I-D 为 draft-ietf-http-v11-spec-rev-00。这项工作于 1999 年完成,并作为 RFC 2616 发布。2007 年之前,IETF 的 HTTP 世界都很平静。
SSL 和 TLS 简史
SSL 2.0 规范在 1995 年左右发布,而 SSL 3.0 则在 1996 年 11 月发布。有趣的是,SSL 3.0 对应的 RFC 6101 于 2011 年 8 月发布。根据 IETF 的说法,这属于“Historic”,即“通常是为了记录那些被考虑过但又被放弃的想法,或者在决定记录它们时就已经是 Historic 的协议”。对于这种情况,拥有一个描述 SSL 3.0 的 IETF 文档是有好处的,因为它可以作为规范在其他地方被引用。
我们更感兴趣的是 SSL 是如何激发了 TLS 的开发,TLS 从 1996 年 11 月开始,I-D 为 draft-ietf-tls-protocol-00。它经历了 6 个草案版本,并在 1999 年初作为 RFC 2246(TLS 1.0)发布。
在 1995 年到 1999 年期间,SSL 和 TLS 协议被用于保护 HTTP 通信。作为一种事实上的标准,这种方式运作得很好。直到 1998 年 1 月,随着 draft-ietf-tls-https-00 的发布,HTTPS 的正式标准化过程才开始。这项工作在 2000 年 5 月结束,发布了 RFC 2616(HTTP over TLS)。
TLS 在 2000 年至 2007 年期间继续演化,出现了 TLS 1.1 和 TLS 1.2。TLS 的下一个版本于 2014 年 4 月被采用,即 draft-ietf-tls-tls13-00。在经历了 28 个草案之后,于 2018 年 8 月成为 RFC 8446(TLS 1.3)。
互联网标准化进程
我希望你能够通过仔细观察时间表了解 IETF 的工作原理。互联网标准的形成大致是这样的:研究人员或工程师设计适合特定用例的实验性协议,然后在不同规模水平公开或私下对协议进行实验。实验数据有助于识别或改进问题。相关工作可能被公开,用于向公众作出解释,收集更广泛的意见,或找到其他实现者。那些采用了早期工作成果的人让实验协议成为了事实上的标准,对实验协议成为正式标准起到了促进作用。
对于正在考虑实现、部署或以某种方式使用协议的组织而言,协议的状态是一个重要的考虑因素。正式的标准化过程会让事实上的标准更具吸引力,因为它会带来更高的稳定性。但需要注意的是,并非所有正式标准化都能获得成功。
确定最终标准的过程几乎与标准本身一样重要。以最初的想法为基础,邀请人们一起来贡献想法,这些人拥有更广泛知识和经验,可以为更广泛的人群带来更有用的东西。但是,标准化过程并不总是那么容易,陷阱和障碍总是存在的。有时候,这个过程需要很长时间,以至于最终得到的结果已经变得不那么重要了。
Cloudflare 的可运行代码
Cloudflare 很自豪能够成为不断发展的新协议的早期采用者。我们很早就开始采用新标准,如 HTTP/2,我们还尝试使用实验性或尚未最终确定的功能,如 TLS 1.3 和 SPDY。
在 IETF 标准化过程中,将可运行的代码部署在跨不同网站的真实网络上可以帮助我们了解协议在真实环境中的运行情况。我们将现有的专业知识和从实验中获得的信息结合起来,用以改进可运行的代码,并向正在标准化协议的工作组反馈有意义的问题和改进意见。
测试新的东西并不是唯一的优先事项。创新者应该知道什么时候该前进,什么时候该把旧的创新抛在脑后。有时候这与面向安全的协议有关,例如,由于 POODLE 漏洞,Cloudflare 默认禁用了 SSLv3。在其他情况下,旧协议会被更先进的新协议所取代,Cloudflare 就使用 HTTP/2 替换了 SPDY。
相关协议的引入和弃用在 Secure Web Timeline 上使用橙色线表示。虚线竖线有助于将 Cloudflare 事件与相关的 IETF 文档关联起来。例如,Cloudflare 在 2016 年 9 月引入了 TLS 1.3 支持,而 RFC 8446 最终版在两年后的 2018 年 8 月发布。
HTTP 重构
HTTP/1.1 是一个非常成功的协议。时间表显示,在 1999 年之后,IETF 就没有太多的动作。然而,真实的情况是,多年的使用经验发现了 RFC 2616 中潜在的问题,这些问题导致了一些互操作性问题。此外,其他 RFC(如 2817 和 2818)扩展了 RFC 2616。2007 年,IETF 决定启动一项新工作,以改进 HTTP 协议规范。这项工作被称为 HTTPbis(“bis”源于拉丁语,意为“两个”、“两次”或“重复”),并成立了新的工作组。原始章程描述了他们试图解决的问题。
简单地说就是 HTTPbis 决定重构 RFC 2616。它将合并勘误修复,并借鉴在此期间发布的其他一些规范的某些方面。他们将文档分成了几个部分,于 2007 年 12 月发布了 6 个 I-D:
- draft-ietf-httpbis-p1-messaging
- draft-ietf-httpbis-p2-semantics
- draft-ietf-httpbis-p4-conditional
- draft-ietf-httpbis-p5-range
- draft-ietf-httpbis-p6-cache
- draft-ietf-httpbis-p7-auth
上图显示了在最终标准化之前,这项工作如何通过长达 7 年的起草过程,发布了 27 个草案版本。2014 年 6 月,发布了所谓的 RFC 723x 系列(其中 x 的范围为从 0 到 5)。HTTPbis 工作组主席用“RFC2616 已死”来庆祝这一成就,也就是说这些新文件将使旧的 RFC 2616 作废。
这与 HTTP/3 有什么关系?
当 IETF 正忙于 RFC 723x 系列时,这个世界并没有停下发展的脚步。人们继续在互联网上增强、扩展和试验 HTTP。其中就包括谷歌,谷歌已经开始试验一种叫作 SPDY(发音为 speedy)的协议。谷歌宣称,这个协议旨在提高 Web 浏览的性能。2009 年底,SPDY v1 发布,很快又在 2010 年推出 SPDY v2。
我不打算深入解释 SPDY 的技术细节,关键的是要知道,SPDY 采用了 HTTP 的核心范式,并对数据交换格式稍作修改。事后看来,HTTP 明确划分了语义和语法。语义描述了请求和响应交换的概念,包括:方法、状态码、标头(元数据)和正文(有效载荷),语法则描述了如何将语义映射到在网络上传输的字节。
HTTP/0.9、1.0 和 1.1 共享了很多语义,还以字符串形式共享了一些语法。SPDY 采用了 HTTP/1.1 语义,并将语法从字符串改为二进制形式。
谷歌的 SPDY 实验表明,他们想要改变 HTTP 语法,但会保留现有的 HTTP 语义。例如,保留https:// 格式的 URL 可以避免很多可能会影响到采用率的问题。
在看到了一些积极的结果后,IETF 认为是时候看看 HTTP/2.0 的效果了。于 2012 年 3 月举行的 IETF 83 大会的一份幻灯片展示了 HTTP/2.0 的需求、目标和成功的衡量标准。它还明确指出“HTTP/2.0 只在传输格式方面与 HTTP/1.x 不兼容”。
在那次会议期间,社区成员被邀请分享他们的提案。提交审议的 I-D 包括 draft-mbelshe-httpbis-spdy-00、draft-montenegro-httpbis-speed-mobility-00 和 draft-tarreau-httpbis-network-friendly-00。最终,SPDY 草案获得通过,并于 2012 年 11 月启动 draft-ietf-httpbis-http2-00 相关工作。在短短两年多的时间内完成了 18 次草案,并于 2015 年发布了 RFC 7540(HTTP/2)。在这期间,HTTP/2 的语法分散到足以使 HTTP/2 和 SPDY 不兼容。
这些年,IETF 一直忙于与 HTTP 相关的工作,HTTP/1.1 重构和 HTTP/2 标准化同时进行。这与 21 世纪初多年的平静形成鲜明对比。
尽管 HTTP/2 正处于标准化阶段,但使用 SPDY 和试验 SPDY 仍然是有好处的。Cloudflare 从 2012 年 8 月起开始支持 SPDY,但在 2018 年 2 月就弃用了。当时的统计数据显示,不到 4%的 Web 客户想要使用 SPDY。2015 年 12 月,我们又推出了 HTTP/2 支持,也就是在 RFC 发布后不久,我们的数据分析表明,有相当一部分 Web 客户端可以使用它。
支持 SPDY 和 HTTP/2 协议的 Web 客户端倾向于使用 TLS。2014 年 9 月推出的通用 SSL 可以确保所有注册到 Cloudflare 的网站都能够在我们引入这些新协议时使用它们。
gQUIC
谷歌在 2012 年至 2015 年期间继续进行实验,并发布了 SPDY v3 和 v3.1。他们也开始研究 gQUIC(当时发音为 quick),并于 2012 年初推出初始版本的规范。
gQUIC 的早期版本使用了 SPDY v3 形式的 HTTP 语法,因为当时 HTTP/2 规范还没有完成。SPDY 二进制语法被打包成可以在 UDP 数据报中发送的 QUIC 数据包,与 HTTP 使用的 TCP 传输有所不同。
SPDY over gQUIC 协议层
gQUIC 使用了一些巧妙的技巧来提升性能,其中之一就是打破应用程序和传输之间的分层界限。这意味着 gQUIC 只支持 HTTP。因此,当时被称为“QUIC”的 gQUIC 被当作 HTTP 的下一个候选版本。尽管 QUIC 在过去几年中不断发生变化,直到今天,人们还是将 QUIC 理解为最初的 HTTP 变体。
有关 gQUIC 的实验继续进行,并最终切换到更接近 HTTP/2 的语法,以至于大多数人直接将其称为“HTTP/2 over QUIC”。但是,由于技术方面的限制,它们之间存在一些非常微妙的差异,比如 HTTP 标头的序列化和交互方式。虽然这是一个很小的差异,但却意味着 HTTP/2 over gQUIC 与 IETF 的 HTTP/2 是不兼容的。
最后,我们始终需要考虑互联网协议的安全性问题。gQUIC 没有使用 TLS,相反,谷歌开发了一种叫作 QUIC Crypto 的方法,可以加快安全握手过程。已经与服务器建立了安全会话的客户端可以重用会话信息来执行“零往返时间”或 0-RTT 握手(0-RTT 后来被 TLS 1.3 采用)。
那么 HTTP/3 到底是什么?
到目前为止,我们应该已经熟悉了标准化过程,也知道了 gQUIC 是什么。2015 年 6 月,谷歌提交了题为“QUIC: A UDP-based Secure and Reliable Transport for HTTP/2”的 draft-tsvwg-quic-protocol-00。它的语法几乎与 HTTP/2 相同。
简单地说,与 IETF 合作的结果就是,QUIC 在传输层似乎提供了很多优势,应该与 HTTP 解耦,因此有必要重新引入分层。此外,有人倾向于返回到基于 TLS 的握手机制(由于在这个时候有关 TLS 1.3 的工作正在进行中,同时也正在整合 0-RTT,所以并没有那么糟糕)。
大约一年后,也就是在 2016 年,提交了一系列新的 I-D:
- draft-hamilton-quic-transport-protocol-00
- draft-thomson-quic-tls-00
- draft-iyengar-quic-loss-recovery-00
- draft-shade-quic-http2-mapping-00
这是另一个 HTTP 和 QUIC 令人感到混淆的地方。draft-shade-quic-http2-mapping-00 的标题是“HTTP/2 Semantics Using The QUIC Transport Protocol”,并将自己描述为“基于 QUIC 的 HTTP/2 语义映射”。但其实这种说法不是很恰当。HTTP/2 在保持语义的同时也在改变语法。此外,“HTTP/2 over gQUIC”已经不能用来准确地描述语法了,至于原因,之前已经提到过了。
IETF 版本的 QUIC 是一个全新的传输协议。这是一个巨大的承诺,在做出这个承诺之前,IETF 希望先看看成员的实际兴趣。为此,2016 年在柏林举行的 IETF 96 大会上召开了正式的“Birds of a Feather”会议。我很幸运能够亲自参加这次会议,还有其他数百人也参加了会议。在会议结束时达成了共识,QUIC 将被 IETF 采用并标准化。
用于将 HTTP 映射到 QUIC 的第一个 IETF QUIC I-D(draft-ietf-quic-http-00)采用了 Ronseal 方法,并将其名称简化为“HTTP over QUIC”。不幸的是,这项工作并没有完全完成,而且在正文中出现了很多次“HTTP/2”。I-D 新编辑 Mike Bishop 发现了这一点,并开始修复 HTTP/2 的命名错误。在 01 草案中,描述被改为“基于 QUIC 的 HTTP 语义映射”。
随着时间的推移和版本的增加,“HTTP/2”一词的使用在逐渐减少。往后推两年,也就是在 2018 年 10 月,I-D 到了第 16 版。虽然 HTTP over QUIC 与 HTTP/2 很相似,但它终究是一个独立的、不向后兼容的 HTTP 语法。对于那些没有密切关注 IETF 开发的人(占了大多数)来说,文档名称并没有体现出这种差异。标准化的要点之一是促进交流和互操作性,然而,像命名这样简单的事情是造成社区混乱的主要原因。
回想一下 2012 年所说的“HTTP/2.0 只在传输格式方面与 HTTP/1.x 不兼容”。IETF 遵循了现有的线索。在 IETF 103 召开之前和召开期间,经过深思熟虑,各方一致同意将“HTTP over QUIC”重命名为 HTTP/3。
但 RFC 7230 和 7231 不同意你对语义和语法的定义!
有时候,文档的标题也会令人感到混淆。描述语法和语义的 HTTP 文档是:
- RFC 7230——超文本传输协议(HTTP/1.1):消息语法和路由
- RFC 7231——超文本传输协议(HTTP/1.1):语义和内容
我们可能会对这些名称进行过多的解读,认为基本的 HTTP 语义是特定于 HTTP 版本的,即 HTTP/1.1。好在 HTTPbis 工作组正在努力解决这个问题。一些成员正在进行另一轮文件修订工作。这项工作现在正在进行当中,被称为 HTTP 核心活动。它将把六份草案压缩成三份:
- HTTP 语义(draft-ietf-httpbis-semantics)
- HTTP 缓存(draft-ietf-httpbis-caching)
- HTTP/1.1 消息语法和路由(draft-ietf-httpbis-messaging)
基于这种新的结构,HTTP/2 和 HTTP/3 成为了通用 HTTP 语义的语法定义。这并不意味着它们除了语法之外就没有自己的特性,但这应该有助于今后的讨论。
总结
这篇文章简要介绍了 HTTP 在过去三十年的标准化过程。我试着在不涉及很多技术细节的情况下解释我们是如何发展到达今天的 HTTP/3 的。如果你想要跳过中间的部分,希望用一句话来概括,那么应该是这样:HTTP/3 只是一种基于 IETF QUIC(一种基于 UDP 的多路复用和安全传输)的新 HTTP 语法。
在这篇文章中,我们介绍了 HTTP 和 TLS 发展过程的重要篇章。我们将全部内容整合到下面的这张 Secure Web Timeline 中。对于喜欢一探究竟的人,请务必查看完整版本,其中包含了草案编号。
微信公众号: 架构师日常笔记 欢迎关注!