问题

HTTP是一个无状态的协议。这句话里的无状态是什么意思?

回答
“HTTP是一个无状态的协议”,这句话听起来有点抽象,但其实用大白话解释就是,HTTP协议本身并不“记仇”也不“记恩”,它每一次请求都像是一次崭新的、独立的会面,不会记得上次我们聊了什么,也不会预设下一次我们会继续聊哪个话题。

打个比方,你走进一家商店。

有状态的商店: 你第一次进去,店员热情地问你喜欢什么,你说了几句,然后出去了。下次你再来,店员一看到你就说:“哎呀,李先生您来了!上次您说喜欢那件蓝色的毛衣对吧?我给您留着呢!” 这种商店记得你,知道你的喜好,提供个性化的服务,这就是“有状态”的服务。

无状态的商店(HTTP协议就像这样的商店): 你第一次进去,店员问你喜欢什么,你说了。你出去了。下次你再来,店员看到你就跟第一次一样,完全不知道你是谁,也不知道你上次买了什么,又会重新问你:“您好,有什么可以帮您的吗?” 这种商店,每一次你进来,都相当于第一次,它不会保存你之前的信息。

回到HTTP协议上来,这就是“无状态”的核心意思:

1. 每一次请求都是独立的: 当你的浏览器发送一个HTTP请求到服务器时(比如你点击一个链接,或者输入一个网址),服务器收到这个请求,然后做出回应,发送数据回来。一旦这个回应发送完毕,服务器就不再保留关于你这次请求的任何信息。下一次你再发送一个请求,对服务器来说,这都是一个全新的请求,就像第一次一样,它不会自动知道这是来自同一个浏览器,或者你之前浏览过哪些页面。

2. 服务器不存储客户端的历史信息: 服务器不会在自己的内存或者数据库里专门为你创建一个“档案”,记录你访问了哪些页面、点击了什么按钮等等。它接收到请求,处理请求,返回响应,然后就“翻篇”了。

3. 客户端(浏览器)需要自己“记着”: 那么问题来了,如果服务器不记得,我们怎么才能在网上看到一个完整的网页,比如登录了之后还能保持登录状态,或者在购物车里添加商品呢?这就是靠客户端(你的浏览器)和一些“小把戏”来弥补的。

Cookie: 最常见的办法就是使用Cookie。当服务器想“记住”你时(比如你登录成功后),它会在给你的响应中包含一些小信息(Cookie),让你的浏览器存起来。下次你再访问这个网站时,浏览器就会自动把之前存的Cookie信息一起发送给服务器。服务器一看,“哦,原来是你,我记得你了!” 就像你随身带着一张“会员卡”去商店,店员一看卡就知道你是谁一样。
Session: 另一种常见的机制是Session。服务器在收到你的第一个请求后,会生成一个唯一的Session ID,然后把这个ID通过Cookie的形式发送给你的浏览器。之后你每次发送请求,浏览器都会带上这个Session ID。服务器通过这个ID就能找到你对应的Session信息(比如你的登录状态、购物车内容等)。这有点像你去一个大型活动,主办方给你发了个手环,手环上有个编号,每次进出或者使用某些服务,看手环编号就知道你是谁了。
URL重写: 有时候,一些状态信息也会被直接嵌入到URL里。

为什么HTTP要设计成无状态的?

你可能会觉得,记不住用户信息挺麻烦的。但HTTP之所以选择无状态,是有它的道理的:

简化设计: 服务器的设计和实现会大大简化。它不需要管理大量的客户端状态信息,降低了复杂性,也减少了出问题的可能性。
可伸缩性强: 当有很多用户同时访问时,服务器不需要为每个用户维护一个庞大的状态列表。任何一个服务器实例都可以处理任何一个请求,这使得系统更容易扩展(比如增加更多服务器来分担压力)。
松耦合: 客户端和服务器之间的耦合度降低。服务器不需要关心客户端的状态,只关心当前的请求本身。

总结一下,HTTP的“无状态”并不是说它完全没有记忆能力,而是说这种记忆能力不是由HTTP协议本身提供的。协议本身只是一个通信的规则,它不负责维护客户端和服务器之间的长期关系。这种“记忆”是通过在协议之外的其他机制(如Cookie、Session)来实现的。

所以,下次听到“HTTP是无状态的”,你可以想象成一个非常高效、不粘人的服务员,每一次都专业地完成你的需求,但从不主动去了解你的过往。你需要他记住什么,就得自己提醒他,或者通过某种方式(比如给他一张名片)来让他识别你。

网友意见

user avatar

有状态意味着状态可持续且可变。如果 HTTP 是有状态的,一个请求发生时可能会导致状态改变,下一个请求发生时它可能要遵循新状态作出不一样的响应。这种情况下,这两个请求不再是独立的,第一个请求是否发生会影响到第二个请求。

无状态意味着 HTTP 这一层是没有记忆的,每一个请求发生时都不需要去回忆过去的请求产生了什么样的记忆,也没办法创造新的记忆去影响将来的请求。这里必须非常明确,无状态的仅仅是 HTTP 这一层,在此之上我们可以搭建有状态的应用层。同时负责多层的服务器也可以是有状态的,只是它在 HTTP 这一层没有状态而已。

这就好比邮政信件是无状态一样,邮局处理每一封信件都是独立的。邮局不会因为来自某个地址的上一封信件没贴够邮票就产生记忆,然后拒绝投递后面所有来自这个地址的信件,直到这个发件地址补够邮资为止。邮局只会拒绝投递邮资不够的那一封信件,这不会影响到其它信件的投递。

尽管信件在邮局这一层是无状态的,写信和收信人之间可以是有状态的。双方可能记得此前的一切通信,可能利用通信之外的其它信息来决定下一封信怎么写。无论是 Cookie 还是其它什么技术手段,在 HTTP 至上搭建有状态的协议并不影响 HTTP 自身无状态。

user avatar

惊讶的发现这个问题已经有好几个大V回答过了,但其实都不太准确。HTTP所谓的“无状态协议”,其实跟Cookies、Session这些都没有什么大的联系,它描述的主要是通信协议层面的问题。

常见的许多七层协议实际上是有状态的,例如SMTP协议,它的第一条消息必须是HELO,用来握手,在HELO发送之前其他任何命令都是不能发送的;接下来一般要进行AUTH阶段,用来验证用户名和密码;接下来可以发送邮件数据;最后,通过QUIT命令退出。可以看到,在整个传输层上,通信的双方是必须要时刻记住当前连接的状态的,因为不同的状态下能接受的命令是不同的;另外,之前的命令传输的某些数据也必须要记住,可能会对后面的命令产生影响。这种就叫做有状态的协议。

相反,为什么说HTTP是无状态的协议呢?因为它的每个请求都是完全独立的,每个请求包含了处理这个请求所需的完整的数据,发送请求不涉及到状态变更。即使在HTTP/1.1上,同一个连接允许传输多个HTTP请求的情况下,如果第一个请求出错了,后面的请求一般也能够继续处理(当然,如果导致协议解析失败、消息分片错误之类的自然是要除外的)可以看出,这种协议的结构是要比有状态的协议更简单的,一般来说实现起来也更简单,不需要使用状态机,一个循环就行了——不过,HTTP本身很复杂,这是另一个故事了,这里暂时不提。

无状态的协议有一些优点,也有一些缺点。

和许多人想象的不同,会话(Session)支持其实并不是一个缺点,反而是无状态协议的优点,因为对于有状态协议来说,如果将会话状态与连接绑定在一起,那么如果连接意外断开,整个会话就会丢失,重新连接之后一般需要从头开始(当然这也可以通过吸收无状态协议的某些特点进行改进);而HTTP这样的无状态协议,使用元数据(如Cookies头)来维护会话,使得会话与连接本身独立起来,这样即使连接断开了,会话状态也不会受到严重伤害,保持会话也不需要保持连接本身。另外,无状态的优点还在于对中间件友好,中间件无需完全理解通信双方的交互过程,只需要能正确分片消息即可,而且中间件可以很方便地将消息在不同的连接上传输而不影响正确性,这就方便了负载均衡等组件的设计。

无状态协议的主要缺点在于,单个请求需要的所有信息都必须要包含在请求中一次发送到服务端,这导致单个消息的结构需要比较复杂,必须能够支持大量元数据,因此HTTP消息的解析要比其他许多协议都要复杂得多。同时,这也导致了相同的数据在多个请求上往往需要反复传输,例如同一个连接上的每个请求都需要传输Host、Authentication、Cookies、Server等往往是完全重复的元数据,一定程度上降低了协议的效率。


话说回来,HTTP协议是无状态协议,这句话本身到底对不对?

实际上,并不全对。HTTP/1.1中有一个Expect: 100-Continue的功能,它是这么工作的:

  1. 在发送大量数据的时候,考虑到服务端有可能直接拒收数据,客户端发出请求头并附带Expect: 100-Continue的HTTP头,不发送请求体,先等待服务器响应
  2. 服务器收到Expect: 100-Continue的请求,如果允许上传,发送100 Continue的HTTP响应(同一个请求可以有任意个1xx的响应,均不是最后的Response,只起到提示性作用);如果不允许,例如不允许上传数据,或者数据大小超出限制,直接返回4xx/5xx的错误
  3. 客户端收到100 Continue的响应之后,继续上传数据

可以看出,这实际上很明显是一个有状态协议的套路,它需要先进行一次握手,然后再真正发送数据。不过,HTTP协议也规定,如果服务端不进行100 Continue的响应,建议客户端在等待较短的时间之后仍然上传数据,以达成与不支持Expect: 100-Continue功能的服务器的兼容,这样可以算是“能有状态则有状态,否则回到无状态的路上”,这样说HTTP 1.x是无状态的协议也是没错的。

至于HTTP/2,它应该算是一个有状态的协议了(有握手和GOAWAY消息,有类似于TCP的流控),所以以后说“HTTP是无状态的协议”就不太对了,最好说“HTTP 1.x是无状态的协议”


===================================================


关于Cookies和有/无状态的关系,如果把有状态、无状态理解成相同的请求是否返回相同的结果,那么要让某个HTTP服务器有状态,真的需要Cookies吗?不需要对不对?只需要大家都共享一个全局状态就行了,比如说首页上有一个访问计数器“您是第XXXX个访问本页的用户”,每访问一次这个计数器就加1,谁访问都加1,这从刚才的理解来说也是“有状态”,对不对?Cookies/Session的作用是创建和维护多组独立的状态,而不是有状态。这个状态指的是后端服务的状态,而非HTTP协议本身的状态。所以说,HTTP协议是无状态的协议,这个其实跟服务的状态是无关的。一个服务不管使用何种协议,都可以在服务层面上是有状态的,因为这和通信协议无关,只需要它在响应请求时改变自己的状态即可,例如有一个Shutdown命令可以直接关掉整个服务器不再接受响应,那么它无论如何都是有状态的对吧。所以说,服务本身有没有状态、支不支持会话,其实跟HTTP协议是否有状态是无关的。

user avatar

综合大家的回答,我觉得举个例子会更好理解一些。

有状态:

A:你今天中午吃的啥?

B:吃的大盘鸡。

A:味道怎么样呀?

B:还不错,挺好吃的。

无状态:

A:你今天中午吃的啥?

B:吃的大盘鸡。

A:味道怎么样呀?

B:???啊?啥?啥味道怎么样?

所以需要cookie这种东西:

A:你今天中午吃的啥?

B:吃的大盘鸡。

A:你今天中午吃的大盘鸡味道怎么样呀?

B:还不错,挺好吃的。

user avatar

其实应用层协议需要结合使用场景和诞生历史来理解。

HTTP这个协议是设计用在万维网上的,那么如果把整个万维网看作是一整个分布式系统,HTTP就是这个分布式系统的基础架构的一种实现。使用最广泛的HTTP1.1的根本指导思想其实来源于REST架构风格,Roy Fielding在他的博士论文Architectural Styles and the Design of Network-based Software Architectures里系统性的阐述了为什么要这样架构万维网。这篇论文阐述的极为精彩,建议有兴趣的话可以读一下。

HTTP设计为无状态的原因在于万维网的设计目标是覆盖全球范围的以网络为核心的超大规模系统,它的操作是通过message本身来进行的,无状态的设计会加强透明度(visibility),稳定度(reliability)和伸缩度(scalability)。提高透明度是因为系统无需通过请求内容以外的信息判断请求的完整内容;提高稳定度是指在部分失败的情况下,减轻了恢复的难度;提高伸缩度的原因是无需储存请求间的状态使服务器端可以很快释放资源并简化实现。

具体的无状态的实现其它答案已经说了很多了,基本就是说HTTP本身不会去追踪请求之间的关系,每一次的请求都是独立的。若要最大化利用HTTP这种基础架构的特性和支持,就是说你要尽量在单次的请求里可以包含所有需求的信息。早期的时候很多设计用了session思想,后来演变为cookie思想,就体现了对REST架构风格的贯彻和对HTTP设计更深入的理解。当然这种转变也可能跟后来网络的普及和廉价化有关,因为无状态风格的设计会加重网络的负担。

HTTP协议是用来给更高层的应用做支持的,因此HTTP就只做到合适的事情为止。HTTP本身不追踪任何请求的关系,因此不管哪个请求对Web服务器都是一样的。如果有对请求追踪的需求,可以放在另一层面实现,现在主流是用Cookie。

类似的话题

本站所有内容均为互联网搜索引擎提供的公开搜索信息,本站不存储任何数据与内容,任何内容与数据均与本站无关,如有需要请联系相关搜索引擎包括但不限于百度google,bing,sogou

© 2025 tinynews.org All Rights Reserved. 百科问答小站 版权所有