这可能是一个令人费解的问题,但是我试图更好地理解无状态。

根据我的阅读,Web应用程序应为无状态的,这意味着每个请求都应视为独立的交易。因此,应避免使用Session和Cookies(因为它们都是有状态的)。更好的方法是使用令牌,令牌是无状态的,因为服务器上没有存储任何内容。

因此,我试图理解,当为数据保留数据时,Web应用程序如何成为无状态的我的会话(例如购物车中的项目)?这些实际上存储在某个地方的数据库中,然后定期清除吗?当您使用令牌而不是cookie时,这如何工作?

然后作为一个相关问题,主要的网站(亚马逊,谷歌,Facebook,Twitter等)实际上是无状态的吗?他们使用令牌还是cookie(或两者都使用)?

评论

我最近看过并与沉迷于无国籍状态的开发者交谈,这使他们分心。对于可重用性而言,无状态是很高兴的,但是在每种情况下都比其他目标都追求该目标是不现实的,除非您出于某种原因(例如扩展)而拥有大量资源来做到这一点。

@MarkRogers为什么?无国籍与可复用性无关。而无状态并不会导致更高的努力。

@PaulWasilewski:无国籍并不会带来更大的努力。 =>确实如此,使用有状态的应用程序,您会将所有内容保留在与会话相关的内存中。尽管可以与会话固定一起使用,但这不能很好地扩展,但是非常简单。当服务器需要开始相互之间交换信息时,麻烦就开始了。

查看亚马逊,您会发现即使更换计算机,您的购物车仍然存在,因此它不会存储在Cookie中,而是存储在数据库中。

如果您没有阅读我的答案。这是简短的版本:Web请求本质上是无状态的。 Web应用程序不是。 (无论什么“无状态网络”教条主义者告诉你!)

#1 楼

“ Web应用程序应该是无状态的”应该理解为“除非有充分的理由拥有状态,否则Web应用程序应该是无状态的”。 “购物车”在设计上是有状态的功能,并且否认这会适得其反。购物车模式的重点是在请求之间保留应用程序的状态。

我可以想象一个实现购物车的无状态网站的替代方案是单页应用程序这样可以使购物车完全保持客户端状态,并通过AJAX调用检索产品信息,然后在用户结帐时立即将其发送到服务器。但是我怀疑我是否曾经见过有人真正这样做过,因为它不允许用户使用多个浏览器选项卡,并且在用户意外关闭选项卡时也无法保留状态。当然,有一些解决方法,例如使用localstorage,但是您确实再次在客户端而不是服务器上具有状态。

每当您有一个Web应用程序需要在浏览量之间保持数据时,通常通过介绍会议来做到这一点。可以通过Cookie或添加到每个链接的URL参数来标识请求所属的会话。应该首选Cookie,因为它们可以使您的URL更加方便,并防止您的用户意外共享其中包含其会话ID的URL。但是,使用URL令牌作为后备对停用Cookie的用户也至关重要。大多数Web开发框架都有一个会话处理系统,它可以立即执行此操作。

在服务器端,会话信息通常存储在数据库中。服务器端内存中缓存是可选的。它可以大大缩短响应时间,但不允许您在不同服务器之间传输会话。因此,您将需要一个持久数据库作为后备。


主要网站(亚马逊,谷歌,Facebook,Twitter等)实际上是无状态的吗?他们使用令牌或cookie(或同时使用两者)吗?


它们是否允许您登录?当您关闭选项卡并重新访问该站点时,您是否仍在登录?如果您是,则他们将使用Cookie来保留会话之间的身份。

评论


我认为这里的困惑之一是,从用户的角度来看,“ Web应用程序”和从“在Web服务器上运行的代码”的狭义上来说,是“ Web应用程序”之间的区别。通常认为后者是无状态的,而不是前者。正如您所说,前者通常是无状态的,因为状态通常是业务逻辑的一部分。对于后者来说,无状态只是意味着状态需要存储在客户端或数据库服务器或这两者上,而不是存储在Web服务器上。

–德里克·埃尔金斯离开东南
17年4月10日在1:19

“ [...]但是您确实又有状态,只是在客户端而不是在服务器上。”这是关于在服务器端没有状态,以实现更好的可伸缩性和可用性。状态是否存储在客户端无关紧要。

– Paul Wasilewski
17年4月10日在9:59

您可以详细说明@ njzk2,这样听起来并不荒谬吗?用户不会去亚马逊购买更多名称。而且,在他们购买商品之后,一些东西消失了,这些东西仅在他们购物时才存在。如果那不是“应用程序的状态”,那是什么?如果应用程序没有状态,那么它们有什么?

–user251748
17年4月10日在14:00

@nocomprende:我认为njzk2的总要旨是,购物车中的内容(如您的全名)是Web应用程序在服务器端持续存在的数据。当人们说“ webapps应该是无状态的”时,它们通常意味着不同于“ webapps不应访问包含与用户名相关联的全名的数据库”。确切地讲,它们对“无状态”的含义可能没有被简单定义,因为一旦有了该数据库,便可以将各种废话保存在其中,以支持过于复杂的应用程序状态,但不应该;-)

–史蒂夫·杰索普(Steve Jessop)
17年4月10日在14:12



@nocomprende:通过回滚数据库来打乱鸡蛋:由于我们的web应用程序是无状态的,因此可以像以前一样恢复;-)

–史蒂夫·杰索普(Steve Jessop)
17年4月10日在14:20

#2 楼

Web应用程序确实应该是无状态的。但是,当会话变量,cookie和令牌都存储在客户端(Web浏览器)上时,它们不会违反此规则。它们可以是请求中的参数。

这是一个简化的模型:

Web Browser (has state) <-> Web Server (stateless) <-> Database (has state)


这可以用于软件工程堆栈交换。我输入的答案是Web浏览器状态的一部分。只要这是唯一的位置,除了我之外,其他任何人都无法访问。但是,一旦我按下Post your Answer,我的浏览器就会将其发送到Web服务器。 Web服务器不使用其自身的状态来处理帖子。它通过浏览器和数据库了解我的身份。检查完我的帖子并将其添加到数据库后,Web服务器会立即忘记我。

这就是无状态的意思。服务器不负责记住任何这些。那不是它的工作。

这样做有很多优点。如果Web服务器内存泄漏,则可以检测到,因为它的内存占用空间不会增加。如果Web服务器崩溃,我的身份将不匹配。如果有人尝试进行拒绝服务攻击,则他们不能使用Web服务器状态资源来进行此操作,因为Web服务器不会在会话之间为他们分配任何状态。这都是为了使Web服务器稳定。这样,当它开始运行时,它将保持运行状态。

现在,我正在消耗数据库中的资源,但是这些资源首先已经通过我可以依靠的稳定工具进行了检查。保护数据库免受狂乱的网络攻击:无状态的业务规则强制Web服务器。

评论


我不知道。。。这个答案听起来有点像在说:“ Excel不会存储您的电子表格,磁盘驱动器会存储!”哈哈,就大多数人而言,数据库不是Web服务器的一部分吗?显然,状态没有存储在CPU或服务器的代码中,并且将其全部保留在内存中是很愚蠢的。

–user251748
17年4月10日在12:17

@nocomprende不,数据库通常不属于Web服务器。是的,将状态存储在数据库中很可能会限制整个应用程序的可伸缩性,但是相对而言,很少有应用程序可以将其所有状态(甚至所有“每个用户”状态)卸载到客户端上。数据库服务器是专门为可伸缩处理状态而设计的,正如CandiedOrange提到的那样,它们通常比Web服务器受到更好的保护,配置和审查。即使不能解决所有可伸缩性问题,轻松扩展Web服务器也有好处。

–德里克·埃尔金斯离开东南
17年4月10日在12:32

@nocomprende:说数据库不是Web服务器的一部分是因为您可以为1个,2个,3个... Web服务器拥有一个数据库(或数据库集群)。这就是无状态意味着增加可伸缩性的方式:您可以独立扩展数据库集群和Web服务器的数量。

– Matthieu M.
17年4月10日在13:50

“ Web应用程序确实应该是无状态的。”不,这是完全废话。

– svidgen
17年4月10日在14:47

这个答案是我最喜欢的答案,因为它最能说明Web开发人员中“无状态”的用法。服务器在请求之间不保持状态。所有状态必须来自客户端(即请求的一部分)或数据库(可能基于请求)。顺便说一句,Web应用程序中通常会存在某种状态(例如,事物的静态实例),但是总的来说,您希望将事物设计为无状态。这个答案似乎比公认的答案更好,因为它实际上最好地解释了无状态的想法。

–凯特
17年4月11日在22:01

#3 楼


Web应用程序应该是无状态的


无意义。 Web请求应该是无状态的。更准确地说,Web请求是无状态的。

但是,说整个应用程序应该是无状态的完全是胡说八道。


每个请求都被视为独立的交易。


是的。或更准确地说,是的,是必须的。通过HTTP,每个请求本质上都独立于所有其他请求。向HTTP添加“状态”要求您为每个“状态”请求显式标识,存储和检索“状态”。而且这很费力,降低了性能,并增加了复杂性。

,由于这些原因,每个可能是无状态的请求都应该是无状态的。


因此,应避免使用Session和Cookies(因为它们
都是有状态的)。更好的方法是使用令牌。


一些注意事项:令牌也可以绑定到会话存储。 Cookies不需要绑定到会话存储。令牌通常存储在cookie中。而且,有时会话只是工作的正确工具。

这意味着,至少有时,会话和cookie与令牌一样“更好”!


[令牌]是无状态的,因为服务器上没有存储任何内容。


就是这样。这就是“无国籍”教条的真正含义。但是,很明显,这不是要在服务器上存储“空”,而是要在服务器上不存储会话状态。例如,我的Gmail收件箱处于一种状态。而且最好将其存储在服务器上!但是,这不是会话状态。

因此,与其让服务器使用可以带一个小标识符并弄清楚自己是谁等的服务器,不如让无状态应用程序提醒您自己是谁以及您是什么。正在处理所有流血的请求。应用程序状态仍然存在,客户端只负责保留它。

现在,如果该状态很小,那可能就可以了。在某些情况下,它非常好。

然后,当然,有些事情我们只是希望成为有状态的...


Web应用程序如何成为当有数据要为我的会话保存时(例如购物车中的物品),该状态为无状态?这些
是否实际存储在某个地方的数据库中,然后定期清除



两种选择。您正在开会,还是被拒绝!

...但是请认真。您通常不会将购物车存储在Cookie中。诸如购物车之类的东西将被存储在“传统”会话中,或者将被存储为Cart对象,并带有服务器用来将其拉入后续请求的某种ID。有点像..呃... ... err ...会话。

认真地说:在很大程度上,当两个通信主体使用“状态”时,我们称之为“状态”可以将对话中的消息情境化。传统上理解的会话是我们通常所说的发生机制。

我认为,无论您使用令牌还是“会话”,对于服务器的每个请求句柄,您要么需要上下文处理该请求以实现它,要么不需要。如果不需要上下文,请不要获取它。如果需要上下文,最好将其放在附近!


然后作为一个相关问题,主要的网站是(亚马逊,谷歌,Facebook,Twitter等)。 )实际上是无状态的?他们是否使用
令牌或cookie(或同时使用两者)?


可能两者都使用。但是,总的来说,它们确实可以完成您的工作:他们设置cookie来识别大型“会话”数据库中的“状态”记录。

我怀疑,如果可能的话,他们会将基本身份声明推入短暂的“令牌”中,以避免在集中式存储上发生不必要的争执。但是,许多服务允许我“注销所有其他位置”这一事实可以很好地表明,如果它们完全使用令牌,那么它们至少会得到半传统会话模型的“支持”。 。

评论


同意。它使我想起“不变数据”的想法。如果它是不变的,则将其刻在一块岩石上,不要浪费计算机来做到这一点。让计算机处理数据!这就是我们建造它们的原因!应用程序处理数据。不变的数据是无用的。

–user251748
17年4月10日在19:47

@nocomprende仅供参考,稍后我将对此做附录。我觉得我的答案缺少了OP基本问题的一部分。因为,在“无状态应用程序”概念背后隐藏着一种合法的关注。但是,答案是,当人们说“无状态”时,他们的意思是“最少地依赖服务器端会话”。

– svidgen
17-4-10在19:53



@nocomprende:不变的数据结构有所不同,它是用于管理内存对象生命周期的工具。

–whatsisname
17年4月11日在2:07

爱你的第一行解释。当我们讨论某些事情时,我们做出的每一个口头陈述都会立即消失。但是以某种方式,我们仍然可以进行对话,是吗?这是魔法!

–user251748
17年4月12日14:48



@nocomprende这是一个有趣的讨论,但是我想我们不应该在这里继续。

– pabrams
18-2-23在16:14



#4 楼

有状态性不一定是一件坏事,但是您需要了解有状态和无状态应用程序之间的区别。简而言之,有状态应用程序会维护有关当前会话的信息,而无状态应用程序则不会。永久存储为用户帐户一部分的信息可能会也可能不会存储在会话中,但是存储与用户帐户有关的信息本身不会使应用程序处于有状态状态。有状态性要求服务器维护有关当前用户会话的信息,而不是客户端浏览器维护的信息。例如,客户端可以进行身份​​验证并获得JSESSIONID cookie,然后将其与每个请求一起发送到服务器。如果服务器根据此JSESSIONID开始将内容存储在应用程序的会话范围内,则该文件将变为有状态的。

无状态

无状态表示服务器和客户端未维护有关用户会话的当前信息。客户端和服务器可以使用某种形式的令牌来提供请求之间的身份验证,但不存储其他任何当前信息。这种解决方案的典型用例可能是新闻站点,其中大多数用户(新消费者)消费信息,但不产生返回该站点的信息。在这种情况下,站点不需要维护有关当前用户会话的任何信息。请注意,网站可能仍会使用Cookie来识别用户并存储有关该用户对网站使用情况的信息,但是由于记录的所有内容都可能是交易性的,因此仍然可能被视为无状态。用户单击了什么链接,该链接可能由服务器记录,但未保留在用户会话中。

服务器上的状态

在服务器上,有状态应用程序保存有关当前用户的状态信息。这种方法通常涉及使用cookie来标识用户的系统,以便可以在两次请求之间在服务器上维护状态。会话可能会或可能不会通过身份验证,具体取决于应用程序的上下文。有状态服务器应用程序具有在服务器上缓存用户状态信息,加快查找和页面响应时间的优势。不利的一面是,将信息存储在会话范围内是昂贵的,并且在规模上它变得非常耗费资源。它还为黑客创建了潜在的攻击媒介,以试图劫持会话标识符并窃取用户会话。有状态服务器应用程序还面临着保护用户会话免受意外服务中断(例如,服务质量)的挑战。服务器故障。解决此问题的常用解决方案是在服务器计算机群集之间群集会话,但是,再次大规模地在所有计算机之间群集所有会话很快变得不切实际。

客户端上的状态

应用程序使用JavaScript和sessionStorage等现代浏览器技术后,应用程序现在可以轻松地在该用户设备上存储有关该用户会话的状态信息。总体而言,该应用程序仍可被认为是有状态的,但维护状态的工作已移至客户端。这种方法(对于Web应用程序的维护者)相对于维护服务器上的状态具有很大的优势,因为每个用户实际上都在维护自己的状态,并且对服务器基础结构没有负担。在网络规模上,这种架构选择会对硬件和电力成本产生巨大影响。维护服务器状态每年可能要花费数百万美元。转移到客户端维护状态的系统,每年可以节省数百万美元。

代币v。cookie

Cookies充当客户端设备/浏览器的标识符。它们可以用来存储所有事物,但是通常它们存储某种形式的标识符,例如CFML应用程序中的CFID / CFTOKEN。可以将Cookie设置为长时间存在于用户的浏览器中,从而可以在浏览器会话之间进行诸如维护应用程序身份验证之类的事情。 Cookie也可以设置为“仅内存”,这样,当用户关闭浏览器时,它们就会过期。

令牌通常是在服务器上生成的(使用加密对信息进行加密的)某种形式的有关用户的标识信息,这些信息传递给客户端,然后与后续请求一起返回给服务器。它们可以在请求和响应的标头中传递,这是单页应用程序中的常见模式。理想情况下,每个请求/响应都会生成一个新令牌,因此攻击者以后无法拦截和使用令牌。

单页应用程序和客户端状态

使用SPA,状态信息会加载到客户端浏览器中并在其中进行维护。状态改变时您将更新发布到您的社交媒体帐户后,客户端会将新交易中继到服务器。在这种情况下,服务器会将更新保存到数据库之类的持久数据存储中,并根据更新(例如,更新ID)将需要与服务器进行同步的任何信息转发回客户端。

请注意,这种在客户端上存储状态的模式为在线/离线体验提供了优势,因为您可以从服务器断开连接,同时仍然拥有一些可用的应用程序。 Twitter是这种情况的一个很好的例子,即使您与Twitter服务器应用程序断开连接,也可以在Twitter feed中查看客户端中加载的所有内容。这种模式还会使服务器和客户端之间的同步变得复杂,这是其自身的全部主题。解决方案的复杂性是在客户端上能够维持状态的权衡。

客户端的状态性使Web应用程序的感觉和行为更像传统的桌面应用程序。与桌面应用程序不同,通常不会在浏览器中将所有帐户信息加载到客户端会话中。这样做在许多情况下是不切实际的,并且会产生不良的经验。您能想象尝试将整个Gmail框加载到浏览器中吗?相反,客户端维护的信息包括您正在查看的标签/文件夹以及您正在查看的文件夹中电子邮件列表中的位置。平衡要维护的状态信息和根据需要请求的状态信息是此模式的另一个工程挑战,并且再次代表了在实用性和提供良好用户体验之间的权衡。

购物车之类的东西

关于购物车之类的细节,实际上取决于解决方案。购物车可以存储在服务器上的数据库中,也可以仅存储在服务器上的会话范围内,甚至可以存储在客户端中。亚马逊拥有针对登录用户的持久性购物车,以及针对匿名用户的“临时”购物车,尽管这些购物车在某种程度上具有持久性。

当您谈论类似Google之类的东西时,实际上是一堆使用同一品牌的不同应用程序,它们可能不共享同一体系结构,并且每种构建方式都可以最满足其用户的需求。如果要了解网站的构建方式,请在浏览器中打开开发人员工具并进行查看。检查cookie,观察网络流量,并查看其运行方式。

很抱歉,这个答案有点混乱,但是有状态性是一个复杂的话题。

#5 楼

不必避免会话和Cookie。您仍然可以在无状态Web应用程序中使用它们。

Java和Ruby on Rails之间有很大的区别。 Java应用程序将使用存储在cookie中的会话密钥将会话存储在内存中。这样可以快速检索用户状态和购物车。但是,您必须始终在会话中访问同一台服务器。

Rails应用程序将用户ID存储在签名的加密cookie中。它不能被篡改。加载页面时,Web应用程序将从数据库中获取您的状态,用户和购物车。这比较慢,但是关键是,您可以击中任何实例!这使您可以随意重启,扩展,关闭实例。很方便。还可以通过共享的内存中缓存数据库(如Redis)使其更快。或者,您也可以将购物车存储在cookie中,前提是它足够小。

因此,您可以通过巧妙的技术实现无国籍状态,并随意扩展规模。

#6 楼

该协议是无状态的。

但是,并不一定因此使用该协议的应用程序应该是无状态的。

以下是两个相关的StackOverflow答案,它们解释了很好的区别:


https://stackoverflow.com/questions/34675027/stateless-web-application-an-urban-legend/34678600#34678600
https:// stackoverflow.com/questions/34675027/stateless-web-application-an-urban-legend/34677668#34677668


#7 楼

当提到无状态时-例如在RESTful HTTP服务中-它将避免在服务器端存储状态。充其量,这还包括避免在数据库或后端的其他持久性存储中存储任何状态。为了清楚起见,我说的是一般而言不是数据的状态。似乎有些人正在混淆。

无状态通信尤其在可伸缩性和可用性方面有很多好处。


更好的方法是使用令牌,由于服务器上没有存储任何内容,因此令牌是无状态的。


是的(对于某些身份验证和授权协议)。令牌可以(但不能本身)提供请求中身份验证用户或授权操作所需的所有信息。例如,请看一下JWT。


因此,我试图理解,当为会话保留数据时,Web应用程序如何成为无状态
。 (例如购物车中的商品)?这些实际上存储在某个地方的数据库中,然后定期清除吗?
当您使用令牌而不是cookie时,该如何工作?


关于购物车示例。在不使用会话或cookie的情况下,将所有购物车项目存储在客户端是没有问题的。您可以在smashingmagazine.com上找到示例。但是也有可能实现带有饼干的无状态购物车(至少如果您的分类不是那么大并且4kb的存储空间足以满足您的需求)。意味着您应该实现无价无限制的购物车。亚马逊或其他大型在线购物平台正在使用状态购物车实施方式,因为用户体验和可用性对他们而言比满足可伸缩性等非功能性技术要求更为重要。

通常,令牌不用于存储购物车项目之类的信息。它们用于无状态身份验证和授权。


然后作为一个相关问题,主要的网站(亚马逊,谷歌,Facebook,Twitter等)实际上是无国籍?他们是否使用
令牌或cookie(或同时使用两者)?


如果您问他们是否使用cookie或令牌进行身份验证,答案是它们同时使用。对于大多数用户,技术客户通常使用cookie,而令牌大多数用于令牌。

#8 楼

好的,您引用的规则在技术上是不正确的。 Web应用程序的所有层都具有状态。

该规则的意图是“不要保留每个会话的状态服务器端”。

,即, ASP,通常用于执行购物篮/用户名中的项目等操作。

原因是随着应用程序获得更多用户,您将耗尽服务器上的内存。将存储移动到数据库或共享缓存并不能解决问题,因为您仍然存在瓶颈。

要保持每个用户的应用程序状态而不遇到问题,请将状态移到客户端。例如,将购物篮中的商品放到Cookie或更高级的客户端存储中。

由于客户端数量随用户数量的增长而扩展,因此整个应用程序不会遇到瓶颈,并且会很好地缩放。

评论


尽管内存泄漏和拒绝服务问题是一个因素,但我认为当今更重要的驱动因素是Web服务器故障的弹性和健壮性,当然,这也与可伸缩性有关。这个想法是,如果服务器超负荷甚至崩溃,我可以将未来的请求(甚至更加小心,甚至重播失败的请求)重新路由到新的Web服务器,而无需协调或丢失状态(如用户所见)。

–德里克·埃尔金斯离开东南
17年4月10日在7:46

嗯。如果服务器上有每个用户的信息,即使它是分布式的,您仍然会遇到可伸缩性问题。

–伊万
17年4月10日在8:38

如果从磁盘中提取数据是诸如缓存之类的瓶颈,那么您可以做很多事情。

– JeffO
17年4月10日在21:07

不,如果您保留每个会话的数据,则存在一个固有的问题。您可以将其从Web服务器移至其自身的高可用性系统,或者通过将其移至客户端来将其全部删除

–伊万
17年4月11日在10:24

所有关于避免生热马铃薯的讨论确实使我迷惑不解。俗话说“降价就停在这里”怎么了?需要某种数据来管理数据,我的银行不希望我将所有财务交易信息仅保留在笔记本电脑上。为什么每个人都逃避数据尖叫?这就是为什么我们有计算机!疯。

–user251748
17年4月12日14:53