HTTP/2是一种无状态协议吗?

24

据我了解,HTTP/2引入一种名为HPACK的有状态头部压缩机制。这是否改变了HTTP协议的无状态语义?对于Web应用程序来说,将HTTP/2视为无状态协议是安全的吗?最后,HTTP/2是否兼容现有的负载均衡器?

2个回答

28

HTTP/2是无状态的

原始的HTTP是一种无状态协议,这意味着每个请求消息可以独立理解。这意味着每个请求都需要带来服务器为了服务该请求所需的所有细节,而无需服务器存储先前请求的大量信息和元数据。

由于HTTP/2不改变这种范式,因此它必须以相同的方式工作,即无状态。

这在RFC文件中也很清楚地可见。其中提到:

超文本传输协议 (HTTP) 是分布式、协作式、超媒体信息系统的应用层协议。它是一个通用、无状态的协议,可用于许多任务...

HTTP/2 的定义也是:

本规范描述了超文本传输协议(HTTP)语义的优化表达,称为 HTTP 版本 2(HTTP/2)... 本规范是 HTTP/1.1 消息语法的替代方案,但并未使既有的 HTTP 语义发生变化。HTTP 的现有语义保持不变。

结论

HTTP/2协议是设计为无状态的,因为相对于原始的 HTTP,语义保持不变。


可能会引起混淆的来源

HTTP/2连接是在TCP连接上运行的应用层协议(顺便说一下,您可以使用UDP进行HTTP传输,但UDP之所以没有使用是因为它不是“可靠的传输”)。不要将其与会话和传输层混淆。 HTTP协议是设计为无状态的。 通过加密的SSL/TLS连接的HTTP也不会改变这种情况,因为HTTPS中的S涉及到传输,而不是协议本身。

HPACK,即HTTP/2的头部压缩格式,是专门为HTTP/2头部设计的一种压缩格式,并在单独的互联网草案中进行了规定。它不会改变HTTP/2本身,因此不会改变语意。

在HTTP/2的RFC中,关于HPACK的章节中,他们指出:

头部压缩具有状态性。一个压缩上下文和一个解压缩上下文只用于整个连接

以下是来自HPACK RFC的原因:

2.2.编码和解码上下文

为了解压头块,解码器只需维护一个动态表(请参阅第2.3.2节)作为解码上下文。没有其他动态状态是需要的。

在双向通信(例如HTTP)中使用时,端点维护的编码和解码动态表是完全独立的,即请求和响应动态表是分开的。


HPACK通过利用诸如HTTP协议中固有的冗余性来减少头字段编码的长度。其最终目标是减少发送HTTP请求或响应所需的数据量。

由于端点必须维护完全独立的编码和解码表,因此HPACK实现无法完全无状态。

同时,有一些库试图解决HPACK问题,例如,一个无状态事件驱动的HPACK编解码器CASHPACK

由于需要维护动态表,因此HPACK实现不能完全无状态。借助于HTTP/2始终解码完整的HPACK序列的假设,通过使用事件驱动API,实现了状态的无状态化。


5
我认为这个回答中的HPACK部分(+1)方向有误。显然,存在状态。但该状态是按连接而非按服务器或会话进行的。每个TCP连接都具有每个连接状态,这并不新鲜。此外,该状态是可消耗的。 - usr
@usr,你的输入很好,关于每个连接的状态,我没有想到这个问题...如果你不介意的话,我会根据你的输入扩展我的答案。谢谢。 - Farside
谢谢@usr @Farside!每个TCP连接的状态都能解释一切 :) 我想在HPACK部分开头提到这一点会更好。 - zeronone
2
@Zamicol,你没有确凿的证据就在臆断。请先学习OSI模型。HTTP/2连接是运行在TCP连接之上的应用层协议(顺便说一句,你可以使用UDP来进行HTTP传输,但UDP不可靠,所以并不常用)。不要将其与会话层和传输层混淆。HTTP协议本质上是无状态的。例如,在加密的SSL/TLS连接上运行的HTTP也不会改变这个声明,因为HTTPS中的S涉及传输而不是协议本身。 - Farside
1
@Farside 正在查看有关HTTP/2协议的Google文档。他们明确强调了HTTP/2支持在一个TCP连接上进行多个流的事实。https://developers.google.com/web/fundamentals/performance/http2/ - Bhavesh
显示剩余5条评论

-1
HTTP/2是有状态的。HTTP 1是无状态的。
理论上,实际上你在日常生活中使用HTTP是有状态的。
尽管在实践中我们已经使用了标准化的有状态机制近三十年,但HTTP 1被俗称为无状态。相反,更诚实的说法应该是“HTTP最初定义了一个无状态的核心,随后加入了许多有状态的补充。现代HTTP的使用是有状态的。”Netscape在1994年引入了Cookie,正式将状态引入到HTTP中。Cookie是首个正式允许HTTP从无状态转变为有状态的手段,但由于Cookie是一种补充,尽管在引入Cookie后,有状态的HTTP很快成为大部分HTTP互联网流量的规范,但人们仍然俗称HTTP为无状态。此外,值得注意的是,在引入Cookie后,我们并没有开始说“HTTP加上Cookie”,而是继续只说“HTTP”,因为人们理解Cookie已经被纳入HTTP标准中,尽管它是一种补充。随着时间的推移,为了提高性能和安全性,还添加了许多其他有状态的组件。
了解这种使用现实,HTTP/2放弃了无状态的目标。许多HTTP/2组件都是有状态的典型代表。与原始的HTTP/1.0不同,HTTP/2在其标准中定义了有状态的组件,因此是有状态的。有状态的组件不再是“附加项”,而是在HTTP/2标准的核心中定义的。HTTP/2中充斥着有状态的组件。错误的“HTTP是无状态”的观念已经过时,远离了HTTP现代有状态的现实。
HTTP/2规范(RFC 7540)中,“state”一词出现了125次,而“stateless”一词没有出现。
以下是有限的、非详尽的HTTP/1和HTTP/2有状态组件列表:
  • HTTP/2 RFC明确表示头部压缩是有状态的
  • HTTP/2的流标识符的目的是为了维护状态。(有一个专门的章节介绍各种状态。)
  • 建立流标识符的HTTP/2 头部是有状态的。(RFC中举了一个例子:“HEADERS帧可以在“空闲”,“保留(本地)”,“打开”或“半关闭(远程)”状态的流上发送。”)
  • HTTP/2的帧是有状态的。RFC中举了一个例子:“特定类型的帧传输可以改变连接的状态。”
  • Cookie是有状态的,规范的标题是“HTTP 状态管理机制”(RFC 6265)
  • 存储密钥的HTTPS是有状态的。此外,CA系统的整个目的是为了HTTPS的状态管理。
  • HTTP身份验证需要状态。(这是如此明显以至于被忽视。)
  • Web存储是有状态的。(这是如此明显以至于被忽视。)
  • HTTP缓存是有状态的。缓存的定义就是有状态的。(这是如此明显以至于被忽视。)
  • 机会性加密是有状态的。
  • URL参数是有状态的。这是在1994年第一个正式的有状态机制(Cookie)出现之前应用程序实现状态的方式。即使不使用任何其他有状态的HTTP功能,如果将URL参数用于状态管理,那么该HTTP应用程序就是有状态的。

第5.1节的HTTP/2 RFC是HTTP/2标准定义的有状态机制的一个很好的例子。

可以安全地假设任意的HTTP/2应用程序是无状态的吗?

HTTP/2是一个有状态的协议,但这并不意味着你的HTTP/2应用程序不能是无状态的。你可以选择忽略有状态的特性以创建无状态的HTTP/2应用程序。

尽管你可以将自己的应用程序定义为无状态的,但不应该假设任意的HTTP/2应用程序都是无状态的。事实上,所有流行的网站如果以无状态方式使用会出错,因此最好的做法是假设一个HTTP/2应用程序是有状态的。

同样适用于HTTP 1。尽管俗称HTTP 1是无状态的,但不能认为任意的HTTP 1应用程序都是无状态的,几乎所有应用程序在尝试无状态使用时都会出现问题。例如,你不能使用无状态的HTTP来使用Facebook。 使用有状态的HTTP是使用Facebook的要求。维基百科、谷歌、WolframAlpha、可汗学院、YouTube、亚马逊、Facebook等等都使用有状态的HTTP。DuckDuckGo可能是唯一一个不需要有状态的HTTP来实现基本功能的流行网站,但是即使如此,没有有状态的HTTP登录和其他功能也会出现问题。

TL;DR:

有状态机制是后来对原始无状态标准的补充。虽然俗称HTTP/1是无状态的,但实际上我们已经使用了近三十年的标准化有状态机制,例如Cookie和缓存。无状态的HTTP在现代世界中并不是很有用或高效,所以与HTTP/1不同,HTTP/2从一开始就定义了有状态组件。特定的HTTP/2应用程序可以忽略HTTP/2的特性来保持无状态,但协议本身预计状态是常态而不是例外。现代的HTTP使用是有状态的。古老的HTTP是无状态的。


4
Cookie会随着每个请求一起发送,因此HTTP是无状态的。在HTTP上运行的应用程序当然是有状态的。但我对HTTP本身很感兴趣,例如如果负载均衡器将连续的请求发送到不同的机器,是否会有任何问题。HTTP/2保持了无状态语义,因此连续的请求被路由到哪个实例或机器并不重要。换句话说,状态仅限于单个TCP连接,连续的连接是独立的。 - zeronone
1
哈哈,Zamicol,你在“HTTP RFC没有关于cookies的说明”上让我笑了...当然没有,难怪!=)你在对主题进行猜测,而没有理解OSI模型。HTTP/1.0是无状态的。HTTP/2也完全如此,因为应用层仍然保持无状态...但是根据RFC,它确实有一些有状态的组件,这也是正确的。一个HTTP/2连接是运行在TCP连接之上的应用层协议。不要将它与会话和传输层混淆。还要阅读@zeronone上面写的内容。给你个踩。 - Farside
2
@zeronone Cookies是有状态的。"随每个请求一起发送"是你的浏览器实现状态的方式。Cookies是在HTTP/1.0之后创建的附加功能。HTTP/2引入了新的有状态机制,超越了HTTP/1.0所实现的内容。 - Zamicol
@Farside “HTTP/2,作为应用层仍然保持无状态...但是根据RFC,它确实有一些有状态的组件。” 我写了你在转述的答案。你将我引用为你争论的来源。stackoverflow.com/a/33681674/1923095 - Zamicol
1
我认为混淆的根源在于你看协议的方向。所有这些对客户端和服务器应用程序都是透明的,通过抽象层至少类似于OSI模型。从JavaScript发出请求并在Python编写的Web应用程序中处理它所需的代码不需要知道使用了哪个HTTP版本以及多少帧流经过各种连接。你说得对,浏览器和客户端需要维护有关连接的状态,但是是否使HTTP/2“有状态”取决于谁在问。 - CodeCaster
125场关于state的比赛证据和0次关于stateless的发现听起来像是一个关于HTTP2的愚蠢学生答案。HTTP/1.1中也提到了statelessstate,在RFC中的命中率为1比42,这是否意味着旧的HTTP比无状态更加有状态?哈哈,真是个笑话!流媒体能力并不意味着有状态性。虽然HTTP/2相对于HTTP/1.1引入了新的功能和优化,如头部压缩和服务器推送,但它并没有从根本上改变HTTP协议的无状态特性,每个请求/响应仍然独立处理,没有状态。 - Farside

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接