当前位置:  开发笔记 > 编程语言 > 正文

如果REST应用程序应该是无状态的,那么如何管理会话?

如何解决《如果REST应用程序应该是无状态的,那么如何管理会话?》经验,为你挑选了10个好方法。

我需要一些澄清.我一直在阅读有关REST和构建RESTful应用程序的内容.根据维基百科,REST本身被定义为具象状态转移.因此,我不理解每个人都在喷涌的所有这种无国籍的gobbledeygook.

来自维基百科:

在任何特定时间,客户端可以在应用程序状态之间转换或"静止".处于休眠状态的客户端能够与其用户进行交互,但不会创建任何负载,并且不会在服务器集或网络上消耗每个客户端存储.

他们只是说不使用会话/应用程序级数据存储???

我知道REST的一个目标是使URI访问一致且可用,例如,而不是在帖子中隐藏分页请求,使请求的页码成为GET URI的一部分.我感觉合理.但似乎只是过分夸大说每个客户端数据(会话数据)都不应该存储在服务器端.

如果我有一个消息队列,并且我的用户想要阅读消息,但是当他阅读它们时,想要阻止某些发送者在其会话期间发出的消息,该怎么办?将它存储在服务器端的某个位置并让服务器只发送未被用户阻止的消息(或消息ID)是不是有意义的?

每次请求新邮件列表时,是否真的必须发送整个邮件发件人列表?与我相关的消息列表首先不会/不应该是公开可用的资源.

再次,只是想了解这一点.有人澄清一下.


更新:

我发现了一个堆栈溢出问题,其答案并不能完全解决这个问题: 如何在REST 中管理状态,该状态表明重要的客户端状态应该在每次请求时都被转移.... Ugg ..似乎很多开销......这是对的吗?



1> 小智..:

基本的解释是:

服务器上没有客户端会话状态.

无状态意味着服务器不存储有关服务器端客户端会话的任何状态.

客户端会话存储在客户端上.服务器是无状态的意味着每个服务器可以随时为任何客户端提供服务,没有会话关联粘性会话.相关会话信息存储在客户端上,并根据需要传递给服务器.

这并不排除Web服务器与之交谈的其他服务维护有关业务对象(如购物车)的状态,而不是客户端当前的应用程序/会话状态.

客户端的应用程序状态不应该被存储在服务器上,而是从身边经过客户的每一个需要它的地方.

这就是在STREST从何而来,状态转移.您转移状态而不是让服务器存储它.这是扩展到数百万并发用户的唯一方法.如果没有其他原因,因为数百万会话是数百万的会话.

会话管理的负载在所有客户端上摊销,客户端存储其会话状态,服务器可以无状态方式为多个数量级或更多客户端提供服务.

即使对于您认为需要成千上万的并发用户的服务,您仍然应该使您的服务无状态.成千上万仍然是成千上万,并且会有与之相关的时间和空间成本.

无状态是HTTP协议和Web通常设计用于操作的方式,并且是一个整体更简单的实现,并且您有一个代码路径而不是一堆服务器端逻辑来维护一堆会话状态.

有一些非常基本的实施原则:

这些原则不是实施,您如何满足这些原则可能会有所不同.

总之,五个关键原则是:

    给每个"东西"一个ID

    把事情联系起来

    使用标准方法

    具有多个表示的资源

    无国籍地沟通

REST 论文中没有关于身份验证或授权的信息.

因为与从非RESTful请求验证RESTful请求没有什么不同.身份验证与RESTful讨论无关.

解释如何为特定需求创建无状态应用程序对于StackOverflow 来说过于宽泛.

实现与REST相关的认证和授权甚至更加广泛,并且在互联网上一般地详细解释了各种实现方法.

要求帮助/信息的评论将/应该被标记为 不再需要.


它不是大胆的体验
@Zak:因为数百万个会话是数百万个会话.关键是要避免所有会话管理的开销.
我的回答中没有任何内容暗示基于每个请求的数据库访问的解决方案,如果您认为这样做,那么您无法理解该规模的身份验证和授权.身份验证可以隐含在状态中,您认为facebook在其REST API的每个请求上都执行"数据库访问"吗?或谷歌这件事?**提示:没有**
这似乎是一个非常大胆的声明,它是*扩展到数百万用户的唯一方式*.为什么服务器端会话不能只是另一种服务?
所以,如果我将用户状态存储在分布式缓存中说memcache,并且我的所有Web服务器现在都不需要存储任何状态但是从memcache获取状态,我可以认为这个应用程序是无状态的吗?
@Jaskey - 不存储客户端状态如何将其视为无状态.这非常简单,客户端必须存储自己的状态并将其传递给需要它的所有系统.客户端总是比您可以负担得起的任何东西都更具可扩展性.
这是我读过的最模糊的答案,我没从中得到任何东西
对于一个应用程序而言,您似乎只希望拥有10,000个并发用户,但使用会话会更有效.10,000个会话不应该是一个服务器的问题,这样就可以避免每次请求都需要数据库访问(用户验证).当您的应用程序需要时,您是否应该转移到完整的REST?

2> Srikar Doddi..:

无状态意味着每个HTTP请求都完全隔离.当客户端发出HTTP请求时,它包含服务器完成该请求所需的所有信息.服务器永远不会依赖先前请求的信息.如果该信息很重要,则客户端必须在后续请求中再次发送该信息.无国籍状态也带来了新的特征.在负载平衡的服务器上分发无状态应用程序更容易.无状态应用程序也很容易缓存.

实际上有两种状态.存在于服务器上的客户端和资源状态的应用程序状态.

当您实际提出请求时,Web服务只需要关心您的应用程序状态.其余的时间,它甚至不知道你存在.这意味着无论何时客户端发出请求,它都必须包含服务器处理它所需的所有应用程序状态.

每个客户端的资源状态都是相同的,其正确位置在服务器上.将图片上传到服务器时,您将创建一个新资源:新图片具有自己的URI,可以成为未来请求的目标.您可以通过HTTP获取,修改和删除此资源.

希望这有助于区分无国籍和各州的意思.


这是一个比第一个更好的答案.
这是否意味着每次发送请求时,客户端都应该发送其用户/密码进行身份验证?因为我想存储一个会话,即使该会话位于所有服务器之间共享的no-sql db上,也不是无状态的吗?

3> S.Lott..:

他们只是说不使用会话/应用程序级数据存储???

不,他们并不是以微不足道的方式说.

他们说不要定义"会话".不要登录.不要退出.为请求提供凭据.每个请求都是独立的.

你还有数据存储.您仍然拥有身份验证和授权.您只是不浪费时间建立会话和维护会话状态.

关键在于每个请求(a)完全独立,(b)可以简单地在没有任何实际工作的情况下耕种到一个巨大的并行服务器场.Apache或Squid可以盲目地成功传递RESTful请求.

如果我有一个消息队列,并且我的用户想要阅读消息,但是当他阅读它们时,想要阻止某些发送者在其会话期间发出的消息,该怎么办?

如果用户想要过滤器,则只需在每个请求上提供过滤器.

让服务器只发送未被用户阻止的消息(或消息ID)是否有意义?

是.在RESTful URI请求中提供过滤器.

每次请求新邮件列表时,是否真的必须发送整个邮件发件人列表?

是.这个"要阻止的邮件发件人列表"有多大?PK的简短列表?

GET请求可能非常大.如有必要,您可以尝试POST请求,即使它听起来像一种查询.


"请勿登录.请勿注销.请提供凭据以获取请求." 我总是在关于如何在REST API中保持无状态的问题中看到这样的响应,而没有关于应该在客户端上存储这些凭据的位置/方式的任何细节.当然我们不应该在本地存储中存储用户名和密码!
@BeniRose能不令牌存储在localStorage的,并使用该令牌将唯一地识别用户的请求?
您使用具有签名的JWT,签名验证很快,因此您可以检查该状态的有效性。

4> Darrel Mille..:

你是绝对正确的,支持与服务器完全无状态的交互确实给客户带来了额外的负担.但是,如果考虑扩展应用程序,则客户端的计算能力与客户端数量成正比.因此,扩展到大量客户端更加可行.

只要您在服务器上承担一点责任来管理与特定客户端交互相关的一些信息,那么这种负担就会迅速增加以消耗服务器.

这是一个折衷.



5> Archimedes T..:
用户应用程序状态管理的历史视图

传统意义上的会话将用户的状态保持在服务器内的应用程序中.这可能是流中的当前页面或先前已输入但尚未持久保存到主数据库的页面.

这种需求的原因是客户端缺乏有效维护状态的标准,而无需特定于客户端(即特定于浏览器)的应用程序或插件.

HTML5和XML标头请求随着时间的推移标准化了在客户端(即浏览器)端以标准方式存储包括应用程序状态的复杂数据的概念,而不需要在服务器之间来回传递.

REST服务的一般用法

当存在需要执行的事务或需要检索数据时,通常会调用REST服务.

REST服务旨在由客户端应用程序调用,而不是直接由最终用户调用.

认证

对于对服务器的任何请求,请求的一部分应包含授权令牌.它是如何实现的是特定于应用程序,但通常是一种BASICCERTIFICATE一种形式的身份验证.

REST服务不使用基于表单的身份验证.但是,如上所述,REST服务并不是由用户调用,而是由应用程序调用.应用程序需要管理获取身份验证令牌.在我的情况下,我使用带有OAuth 2.0的JASPIC的 cookie 连接到Google进行身份验证和简单的HTTP身份验证以进行自动化测试.我还通过JASPIC使用HTTP Header身份验证进行本地测试(尽管可以在SiteMinder中执行相同的方法)

根据这些示例,身份验证在客户端进行管理(虽然SiteMinder或Google会在其末尾存储身份验证会话),但对于该状态无法做任何事情,但它不是REST服务应用程序的一部分.

检索请求

REST中的检索请求GET是请求特定资源并且可缓存的操作.不需要服务器会话,因为请求具有检索数据所需的一切:身份验证和URI.

交易脚本

如上所述,客户端应用程序本身也调用REST服务以及它在客户端管理的身份验证.

对于REST服务[如果正确完成],这意味着对REST服务器采取单个请求将包含单个用户操作所需的所有内容,该操作执行单个事务中所需的所有操作,事务脚本就是模式叫做.

POST通常是通过请求完成的,但PUT也可以使用其他类似的请求.

很多人为设想的REST示例(我自己这样做)试图跟随HTTP协议中定义的内容,经过我决定更务实并将其留给GET和POST.该POST方法甚至不必实现POST-REDIRECT-GET模式.

无论如何,正如我上面提到的,客户端应用程序将是调用服务的应用程序,它只会POST在需要时(不是每次都)使用所有数据调用请求.这可以防止对服务器的持续请求.

轮询

虽然REST也可以用于轮询,但我不推荐它,除非你因浏览器兼容性而必须使用它.为此,我将使用我设计了API合同的 WebSockets .CometD是旧版浏览器的另一种选择.



6> CommaToast..:

REST非常抽象.它有助于拥有一些好的,简单的,真实的例子.

以所有主要社交媒体应用程序为例--Tumblr,Instagram,Facebook和Twitter.它们都有一个永久滚动的视图,您向下滚动的距离越远,您看到的内容越多,越往后退.但是,我们都经历过那些你失去滚动位置的那一刻,应用程序会将你重置回顶部.就像你退出应用程序一样,当你重新打开它时,你又回到了顶端.

之所以如此,是因为服务器没有存储你的会话状态.可悲的是,您的滚动位置只是存储在客户端的RAM中.

幸运的是,您不必在重新连接时重新登录,但这只是因为您的客户端也存储了登录证书尚未过期.删除并重新安装应用程序,您将不得不重新登录,因为服务器未将您的IP地址与您的会话相关联.

您没有在服务器上登录会话,因为他们遵守REST.


现在上面的示例根本不涉及Web浏览器,但在后端,应用程序通过HTTPS与其主机服务器进行通信.我的观点是REST不必涉及cookie和浏览器等.存在各种存储客户端会话状态的方法.

但是让我们谈谈Web浏览器一秒钟,因为这带来了REST的另一个主要优势,这里没有人在谈论.

如果服务器试图存储会话状态,那么它应该如何识别每个客户端?

它无法使用其IP地址,因为许多人可能在共享路由器上使用相同的地址.那怎么样呢?

它不能使用MAC地址有很多原因,其中最重要的原因是你可以在不同的浏览器和应用程序上同时登录多个不同的Facebook帐户.一个浏览器可以很容易地假装成另一个浏览器,并且MAC地址也很容易欺骗.

如果服务器必须存储一些客户端状态以识别您的身份,则必须将其存储在RAM中,而不仅仅是处理请求所花费的时间,否则它必须缓存该数据.服务器具有有限的RAM和缓存,更不用说处理器速度.服务器端状态以指数方式添加到所有三个状态.此外,如果服务器要存储有关您的会话的任何状态,那么它必须为您当前登录的每个浏览器和应用程序单独存储它,以及您使用的每个不同设备.


所以......我希望你现在看到为什么REST对可扩展性如此重要.我希望你能开始明白为什么服务器端会话状态对服务器的可扩展性是什么焊接的铁砧对汽车加速.


人们感到困惑的地方是认为"状态"是指存储在数据库中的信息.不,它指的是在您使用服务器时需要在服务器的RAM中的任何信息.



7> Sam Sirry..:

我看到这里的基本问题是将SessionState混合在一起.虽然REST指定您不应将State存储在服务器上,但没有任何东西阻止您存储用户Session.

在服务器上管理状态意味着您的服务器确切知道客户端正在做什么(他们在应用程序的哪个部分查看的页面).这是你不应该做的.

我同意其他人说你应该把会话存储保持在最小尺寸; 虽然这是常识,但它实际上也依赖于应用程序.因此,简而言之,您仍然可以使用缓存数据保持会话,以便在服务器上以较少的负载处理请求,并通过为客户端提供临时身份验证/访问令牌来管理身份验证.每当会话/令牌过期时,生成一个新会话/令牌并要求客户端使用它.

有人可能会争辩说客户端应该更好地生成令牌.我说它有两种方式,它取决于应用程序,以及谁将使用API​​.

在服务器上保留一些敏感的会话数据应该是正确的方法.您不能相信客户端保留其购物车(例如)包含名为"isFreeGift"的字段.此类信息应保存在服务器上.

Santanu Dey在他的回答中提供的视频链接很有帮助.如果你没有,请留意.

只是旁注:似乎已经给出的所有答案似乎都忽略了某些操作可能会导致服务器负载过重的事实.这与功耗,硬件消耗和成本(由CPU周期租用的服务器)相关.一个好的开发人员不应该懒得优化他们的应用程序,即使在一些租用的服务器上的现代CPU上可以非常快速地完成操作,而他们不支付电费和维护费用.

Althoght这个问题已经有几年了,我希望我的回答仍然有用.


我普遍同意这种观点,但最近有一种趋势是声称甚至会话标识符也不应存储在服务器上.我还没有找到替代解决方案是什么,JWT受到了很好的吹捧,但还有一些问题:http://cryto.net/~joepie91/blog/2016/06/19/stop-using-jwt - 适用的会话部分-2-为什么 - 您的解决方案 - 犯规 - 工作/

8> 小智..:

无状态意味着服务状态不会在后续请求和响应之间持续存在.每个请求都带有自己的用户凭据,并且单独进行身份验证.但在有状态中,每个请求都可以从任何先前的请求中获知.所有有状态请求都是面向会话的,即每个请求都需要知道并保留先前请求中所做的更改.

银行应用程序是有状态应用程序的一个示例.用户首次登录然后进行交易并注销.如果在注销后用户将尝试进行交易,他将无法这样做.

是的,http协议本质上是一个无状态协议,但为了使其成为有状态,我们使用HTTP cookie.所以,默认情况下是SOAP.但它同样可以成为有状态,取决于您使用的框架.

HTTP是无状态的,但我们仍然可以通过使用不同的会话跟踪机制在我们的Java应用程序中维护会话.

是的,我们也可以在webservice中维护会话,无论是REST还是SOAP.它可以通过使用任何第三方库来实现,也可以由我们自己实现.

摘自http://gopaldas.org/webservices/soap/webservice-is-stateful-or-stateless-rest-soap



9> dkellner..:

没有勺子。

不要将无状态视为“ 一次又一次将所有内容发送到服务器”。没门。总会有状态-数据库本身毕竟一种状态,您是注册用户,因此没有服务器端,任何一组客户端信息都将无效。从技术上讲,您永远不会真正处于无国籍状态。

每次辩论都在登录上说一句话

不保留会话并每次登录都不意味着什么?有些意思是“每次发送密码”,这简直是愚蠢的。有人说“当然不行,而是发送令牌 ”-瞧,PHP会话几乎就是这样做的。它会发送一个会话ID,这是一种令牌,它可以帮助您找到自己的个人资料,而不必每次都重新发送u / pw。它也相当可靠且经过了良好的测试。是的,很方便,这可能会带来缺点,请参阅下一段。

减少占地面积

相反,您应该做的事以及真正有意义的事,是将Web服务器的占用空间减至最少。像PHP这样的语言使将所有内容填充到会话存储中变得非常容易-但是会话具有价格标签。如果您有多个Web服务器,则它们需要共享会话信息,因为它们也共享负载-它们中的任何一个都可能必须处理下一个请求。

共享存储是必须的。服务器至少需要知道某人是否已登录。(而且,如果您每次都要决定数据库时都在打扰数据库,那么您几乎注定要失败。)共享存储需要比数据库快很多。这带来了诱惑:好的,我的存储空间非常快,为什么不在那里存储所有内容?-这就是相反的情况。

所以您说的是,将会话存储空间降到最低?

同样,这是您的决定。出于性能原因,您可以在此处存储内容(数据库几乎总是比Redis慢),可以冗余地存储信息,实现自己的缓存,无论如何-请记住,如果您存储大量垃圾,Web服务器将具有更大的负载在他们。而且,如果它们在重负荷下破裂(并且会破裂),您将丢失有价值的信息;使用REST的思维方式,在这种情况下发生的所有事情就是客户端再次发送相同的(!)请求,并且这次得到了服务。

那怎么办呢?

这里没有万能的解决方案。我会说选择无国籍水平,然后再去做。会议可能会受到某些人的喜爱而受到其他人的讨厌,但它们没有任何进展。对于每个请求,发送尽可能多的信息,也许更多;但不要将无状态视为没有会话,也不能解释为每次都在登录。服务器必须以某种方式知道是你自己;PHP会话ID是一种好方法,手动生成的令牌是另一种方法。

思考和决定,不要让设计趋势为您考虑。



10> Santanu Dey..:

看看这个演示文稿.

http://youtu.be/MRxTP-rQ-S8

根据这种模式 - 创建瞬态的休息资源来管理状态,如果真的需要的话.避免明确的会话.

推荐阅读
ifx0448363
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有