• 耀世娱乐注册
  • 耀世娱乐登录
  • 耀世娱乐招商QQ
  • HTTP是一个无状态的协议。这句话里的无状态是什么意思?

    作者:admin发表时间:2023-07-31

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

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

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

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

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

      在发送大量数据的时候,考虑到服务端有可能直接拒收数据,客户端发出请求头并附带Expect: 100-Continue的HTTP头,不发送请求体,先等待服务器响应

      服务器收到Expect: 100-Continue的请求,如果允许上传,发送100 Continue的HTTP响应(同一个请求可以有任意个1xx的响应,均不是最后的Response,只起到提示性作用);如果不允许,例如不允许上传数据,或者数据大小超出限制,直接返回4xx/5xx的错误

      可以看出,这实际上很明显是一个有状态协议的套路,它需要先进行一次握手,然后再真正发送数据。不过,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协议是否有状态是无关的。

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

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

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

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

      无状态(Stateless)魔都的老王开了一个会所,一个开会的地方,有大会议室、小会议室、Cosplay情景会议室。顾客听说这个会所有特色,于是纷纷前来消费,小明就是其中的一员。小明上次会议室体验很棒,尽管有点贵,本周又前来消费。结账时,小明以为老王认识自己,和老王套近乎弄个优惠价:“王老板,我上周刚来过,打个折扣呗”!老王很茫然地瞅着小明:“上周你来过?我好像一点印象也没有了嘛,很抱歉,无法优惠”!小明很不爽地付完钱走人…有状态(Stateful)老王有一个助手叫小王,看到这一幕于是和老板有一番对话:小王:老板,下次客人来消费,咱们给客人发一张小卡片,来一次打卡一次,凡是打过卡的,都有优惠。来的次数越多,折扣力度越大,这样就能有更多的回头客,您看如何?老王连说这是好主意,以后就这么干!小明第一次来领了一张考勤卡,打了卡夹在钱包里。第二次来消费埋单时,小明从自己的钱包掏出考勤卡,老王一看原来是回头客,好说好说,88折优惠,小明和老王都笑的合不拢嘴…Cookie后来老王觉得考勤卡上,还应该多记录一些内容,才能更好地服务客户,考勤卡上慢慢增加了更多内容:会员卡片样例

      小明再次来消费时,不仅可以优惠,还可以根据小明的消费习惯,做出最合理的安排。

      随着服务的精细化,小卡片上描述客户的信息越来越多,卡片越做越大,由于小卡片受4K字节的限制,每次客户前来消费都要携带大大的卡片,这很夸张!

      小王寻思着,小卡片一直都是客户携带,为何不在公司的电脑上弄个数据库,记录客户的消费习惯,每个客户有一个数据库明细:

      给小明的小卡片上只要有一个客户代号“08029snne3e0kekll0jeis007”就可以了,查询电脑就可以知道是小明,消费完还可以从账户余额内扣除。

      http最初的设计是无状态的(stateless),但是无状态的http无法满足互联网日益发展的需求,于是业界扩展了http协议,增加了有状态(stateful)协议头,使之变成一个有状态协议。

      这个有状态的协议头,就是依靠Cookie来实现的,Cookie是维系客户端与服务器之间状态同步的纽带。

      所谓状态同步,通俗地说就是“记忆同步”,英语的常用表达则为“Keep in the same page”!

      无论什么类型的Cookie,都是由服务器来一手创建,最终解释权归服务器,只有服务器才理解这些Cookie所代表的真正涵义;客户只负责携带,不需要理解Cookie的真正意义!

    联系方式

    电话:400-123-4567

    Email: admin@baidu.com

    传真:+86-123-4567

    手机:13888888888