我需要一些澄清。 我一直在阅读有关REST和构建RESTful应用程序的内容。 根据维基百科,REST本身被定义为具象国家转移 。 因此,我不理解每个人都在喷涌的所有这种无国籍的gobbledeygook 。
来自维基百科:
在任何特定时间,客户端可以在应用程序状态之间转换或“静止”。 处于休眠状态的客户端能够与其用户进行交互,但不会创建任何负载,并且不会在服务器集或网络上消耗每个客户端的存储。
他们只是说不使用会话/应用程序级数据存储???
我知道REST的一个目标是使URI访问一致且可用,例如,而不是在帖子中隐藏分页请求,使请求的页码成为GET URI的一部分。 我感觉合理。 但似乎只是过分夸大说每个客户端数据 (会话数据)都不应该存储在服务器端。
如果我有一个消息队列,并且我的用户想要阅读消息,但是当他阅读它们时,想要阻止某些发送者在其会话期间发出的消息,该怎么办? 将它存储在服务器端的某个位置并让服务器只发送未被用户阻止的消息(或消息ID)是不是有意义的?
每次请求新邮件列表时,是否真的必须发送整个邮件发件人列表? 与我相关的消息列表首先不会/不应该是公开可用的资源。
再次,只是想了解这一点。 有人请澄清一下 。
更新:
我发现了一个堆栈溢出问题,其答案并不能完全解决问题: 如何在REST中管理状态 ,该状态表明重要的客户端状态应该在每次请求时都被转移.... Ugg ..似乎很多开销......这是对的吗?
看看这个演示文稿。
http://youtu.be/MRxTP-rQ-S8
根据这种模式 - 创建瞬态的休息资源来管理状态,如果真的需要的话。 避免明确的会话。
整个概念是不同的......如果您尝试实现RESTFul协议,则无需管理会话。 在这种情况下,最好在每个请求上执行身份验证过程(而在性能方面会有额外的成本 - 散列密码将是一个很好的例子。不是很重要......)。 如果您使用会话 - 如何在多个服务器之间分配负载? 我敢打赌RESTFul协议意味着消除任何会话 - 你真的不需要它们......这就是它被称为“无国籍”的原因。 只有在完成请求后才能在客户端存储除Cookie以外的任何内容时才需要会话(以旧的,非Javascript / HTML5支持的浏览器为例)。 对于“全功能”RESTFul客户端,通常可以安全地在客户端(内存中)存储base64(login:password)
,直到仍然加载应用程序 - 该应用程序用于访问唯一的主机和cookie不能被第三方脚本妥协......
我强烈建议禁用RESTFul服务的cookie身份验证...查看基本/摘要身份验证 - 这应该足够基于RESTFul的服务。
传统意义上的会话将用户的状态保持在服务器内的应用程序中。 这可能是流中的当前页面或先前已输入但尚未持久保存到主数据库的页面。
这种需求的原因是客户端缺乏有效维护状态的标准,而无需特定于客户端(即特定于浏览器)的应用程序或插件。
HTML5和XML标头请求随着时间的推移标准化了在客户端(即浏览器)端以标准方式存储包括应用程序状态的复杂数据的概念,而不需要在服务器之间来回传递。
当存在需要执行的事务或需要检索数据时,通常会调用REST服务。
REST服务旨在由客户端应用程序调用,而不是直接由最终用户调用。
对于对服务器的任何请求,请求的一部分应包含授权令牌。 它是如何实现的是特定于应用程序,但通常是BASIC
或CERTIFICATE
形式的身份验证。
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是旧版浏览器的另一种选择。
无状态意味着服务状态不会在后续请求和响应之间持续存在。 每个请求都带有自己的用户凭据,并且单独进行身份验证。 但在有状态中,每个请求都可以从任何先前的请求中获知。 所有有状态请求都是面向会话的,即每个请求都需要知道并保留先前请求中所做的更改。
银行应用程序是有状态应用程序的一个示例。 用户首次登录然后进行交易并注销。 如果在注销后用户将尝试进行交易,他将无法这样做。
是的,http协议本质上是一个无状态协议,但为了使其成为有状态,我们使用HTTP cookie。 所以,默认情况下是SOAP。 但它同样可以成为有状态,取决于您使用的框架。
HTTP是无状态的,但我们仍然可以通过使用不同的会话跟踪机制在我们的Java应用程序中维护会话。
是的,我们也可以在webservice中维护会话,无论是REST还是SOAP。 它可以通过使用任何第三方库来实现,也可以由我们自己实现。
摘自http://gopaldas.org/webservices/soap/webservice-is-stateful-or-stateless-rest-soap
您必须在客户端管理客户端会话。 这意味着您必须为每个请求发送身份验证数据,并且您可能(但不一定)在服务器上有内存缓存,这会将身份验证数据与身份,权限等用户信息相关联......
这种REST 无状态约束非常重要。 如果不应用此约束,您的服务器端应用程序将无法很好地扩展 ,因为维护每个客户端会话将是其致命弱点 。
无状态与有状态之间的主要区别是每次都将数据传递回服务器。 在无状态的情况下,客户端必须提供所有信息,因此可能需要在每个请求中传递大量参数。 在Stateful中,cliet传递这些参数一次,它们由服务器维护,直到客户端再次修改。
IMO,API应该是无状态的,这允许允许快速扩展。
服务器上没有客户端会话状态。
无状态意味着服务器不存储有关服务器端客户端会话的任何状态。
客户端会话存储在客户端上。 服务器是无状态的意味着每个服务器可以随时为任何客户端提供服务,没有会话关联或粘性会话 。 相关会话信息存储在客户端上,并根据需要传递给服务器。
这并不排除Web服务器与之交谈的其他服务维护有关业务对象(如购物车)的状态,而不是客户端当前的应用程序/会话状态。
客户端的应用程序状态永远不应该存储在服务器上,而是从客户端传递到需要它的每个地方。
这就是REST中的ST来自State Transfer 。 您转移状态而不是让服务器存储它。 这是扩展到数百万并发用户的唯一方法。 如果没有其他原因,因为数百万会话是数百万的会话。
会话管理的负载在所有客户端上摊销,客户端存储其会话状态,服务器可以无状态方式为多个数量级或更多客户端提供服务。
即使对于您认为只需要成千上万的并发用户的服务,您仍然应该使您的服务无状态。 成千上万仍然是成千上万,并且会有与之相关的时间和空间成本。
无状态是HTTP协议和Web通常设计用于操作的方式,并且是一个整体更简单的实现,并且您有一个代码路径而不是一堆服务器端逻辑来维护一堆会话状态。
这些原则不是实施,您如何满足这些原则可能会有所不同。
总之, 五个关键原则是:
因为与从非RESTful请求验证RESTful请求没有什么不同。 身份验证与RESTful讨论无关。
解释如何为特定需求创建无状态应用程序对于StackOverflow来说过于宽泛 。
实现与REST相关的认证和授权甚至更加广泛,并且在互联网上一般地详细解释了各种实现方法。
要求帮助/信息的评论将/应该被标记为不再需要 。
他们只是说不使用会话/应用程序级数据存储???
不,他们并不是以微不足道的方式说。
他们说不要定义“会话”。 不要登录。 不要退出。 为请求提供凭据。 每个请求都是独立的。
你还有数据存储。 您仍然拥有身份验证和授权。 您只是不浪费时间建立会话和维护会话状态。
关键在于每个请求(a)完全独立,(b)可以简单地在没有任何实际工作的情况下耕种到一个巨大的并行服务器场。 Apache或Squid可以盲目地成功传递RESTful请求。
如果我有一个消息队列,并且我的用户想要阅读消息,但是当他阅读它们时,想要阻止某些发送者在其会话期间发出的消息,该怎么办?
如果用户想要过滤器,则只需在每个请求上提供过滤器。
让服务器只发送未被用户阻止的消息(或消息ID)是否有意义?
是。 在RESTful URI请求中提供过滤器。
每次请求新邮件列表时,是否真的必须发送整个邮件发件人列表?
是。 这个“要阻止的邮件发件人列表”有多大? PK的简短列表?
GET请求可能非常大。 如有必要,您可以尝试POST请求,即使它听起来像是一种查询。
你是绝对正确的,支持与服务器完全无状态的交互确实给客户带来了额外的负担。 但是,如果考虑扩展应用程序,则客户端的计算能力与客户端数量成正比。 因此,扩展到大量客户端更加可行。
只要您在服务器上承担一点责任来管理与特定客户端交互相关的一些信息,那么这种负担就会迅速增加以消耗服务器。
这是一个折衷。
无状态意味着每个HTTP请求都完全隔离。 当客户端发出HTTP请求时,它包含服务器完成该请求所需的所有信息。 服务器永远不会依赖先前请求的信息。 如果该信息很重要,则客户端必须在后续请求中再次发送该信息。 无国籍状态也带来了新的特征。 在负载平衡的服务器上分发无状态应用程序更容易。 无状态应用程序也很容易缓存。
实际上有两种状态。 存在于服务器上的客户端和资源状态的应用程序状态。
当您实际提出请求时,Web服务只需要关心您的应用程序状态。 其余的时间,它甚至不知道你存在。 这意味着无论何时客户端发出请求,它都必须包含服务器处理它所需的所有应用程序状态。
每个客户端的资源状态都是相同的,其正确位置在服务器上。 将图片上传到服务器时,您将创建一个新资源:新图片具有自己的URI,可以成为未来请求的目标。 您可以通过HTTP获取,修改和删除此资源。
希望这有助于区分无国籍和各州的意思。
我看到这里的基本问题是将Session与State混为一谈 。 虽然REST指定您不应将State存储在服务器上,但没有任何东西阻止您存储用户Session 。
在服务器上管理状态意味着您的服务器确切知道客户端正在做什么(他们在应用程序的哪个部分查看的页面)。 这是你不应该做的。
我同意其他人说你应该把会话存储保持在最小尺寸; 虽然这是常识,但它实际上也依赖于应用程序。 因此,简而言之,您仍然可以使用缓存数据保持会话,以便在服务器上以较少的负载处理请求,并通过为客户端提供临时身份验证/访问令牌来管理身份验证。 每当会话/令牌过期时,生成一个新会话/令牌并要求客户端使用它。
有人可能会争辩说客户端应该更好地生成令牌。 我说它有两种方式,它取决于应用程序,以及谁将使用API。
在服务器上保留一些敏感的会话数据应该是正确的方法。 您不能相信客户端保留其购物车(例如)包含名为“isFreeGift”的字段。 此类信息应保存在服务器上。
Santanu Dey在他的回答中提供的视频链接很有帮助。 如果你没有,请留意。
只是旁注:似乎已经给出的所有答案似乎都忽视了某些操作可能会导致服务器负载过重的事实。 这与功耗,硬件消耗和成本(由CPU周期租用的服务器)相关。 一个优秀的开发人员不应该懒得优化他们的应用程序,即使在一些租用的服务器上的现代CPU上可以非常快速地完成操作,而他们不支付电费和维护费用。
Althoght这个问题已经有几年了,我希望我的回答仍然有用。
REST非常抽象。 它有助于拥有一些好的,简单的,真实的例子。
以所有主要社交媒体应用程序为例--Tumblr,Instagram,Facebook和Twitter。 它们都有一个永久滚动的视图,您向下滚动的距离越远,您看到的内容越多,时间越早越远。 但是,我们都经历过那些你失去滚动位置的那一刻,应用程序会将你重置回顶部。 就像你退出应用程序一样,当你重新打开它时,你又回到了顶端。
之所以如此,是因为服务器没有存储你的会话状态。 可悲的是,您的滚动位置只是存储在客户端的RAM中。
幸运的是,您不必在重新连接时重新登录,但这只是因为您的客户端也存储了登录证书尚未过期。 删除并重新安装应用程序,您将不得不重新登录,因为服务器未将您的IP地址与您的会话相关联。
您没有在服务器上登录会话,因为他们遵守REST。
现在上面的示例根本不涉及Web浏览器,但在后端,应用程序通过HTTPS与其主机服务器进行通信。 我的观点是REST不必涉及cookie和浏览器等。存在各种存储客户端会话状态的方法。
但是让我们谈谈Web浏览器一秒钟,因为这带来了REST的另一个主要优势,这里没有人在谈论。
如果服务器试图存储会话状态,那么它应该如何识别每个客户端?
它无法使用其IP地址,因为许多人可能在共享路由器上使用相同的地址。 那怎么样呢?
它不能使用MAC地址有很多原因,其中最重要的原因是你可以在不同的浏览器和应用程序上同时登录多个不同的Facebook帐户。 一个浏览器可以很容易地假装成另一个浏览器,并且MAC地址也很容易欺骗。
如果服务器必须存储一些客户端状态以识别您的身份,则必须将其存储在RAM中,而不仅仅是处理请求所花费的时间,否则它必须缓存该数据。 服务器具有有限的RAM和缓存,更不用说处理器速度。 服务器端状态以指数方式添加到所有三个状态。 此外,如果服务器要存储有关您的会话的任何状态,那么它必须为您当前登录的每个浏览器和应用程序单独存储它,以及您使用的每个不同设备。
所以......我希望你现在看到为什么REST对可扩展性如此重要。 我希望你能开始明白为什么服务器端会话状态对服务器的可扩展性是什么焊接的铁砧对汽车加速。
人们感到困惑的地方是认为“状态”是指存储在数据库中的信息。 不,它指的是在您使用服务器时需要在服务器的RAM中的任何信息。
REST是无状态的,并且不会在请求之间保持任何状态。 客户端cookie /标头设置为维护用户状态,如身份验证。 假设客户端用户名/密码通过第三方认证机制验证 - 二级OTP生成等。一旦用户获得认证 - 标题/ cookie进入休息服务端点暴露,我们可以假设用户为auth,因为用户带有有效的标题/ cookie 。 现在,像IP这样的用户的某些信息要么保留在缓存中,之后如果请求来自相同的Ip(mac地址)列出的资源,则允许用户。 并且缓存在某个特定时间内保持不变,一旦时间过去就会失效。 因此,可以使用缓存,也可以使用DB条目来保存请求中的信息。
不要把无状态视为“一次又一次地将所有东西发送到服务器”。 没门。 会有状态,总是 - 数据库本身毕竟是一种状态,你是一个注册用户,所以任何一组客户端信息都没有服务器端无效。 从技术上讲,你永远不会真正无国籍。
什么甚至意味着不保持会话并每次登录? 有些人的意思是“每次都发送密码”,这只是简单的愚蠢。 有人说“当然不是,不要发送令牌 ” - 请注意,PHP会话几乎就是这样做的。 它会发送一个会话ID ,这是一种令牌 ,它可以帮助您在不重新发送u / pw的情况下访问您的个人资料。 它也非常可靠且经过良好测试。 是的,方便,这可能会变成一个缺点,见下一段。
您应该做的事情 ,以及真正意义上的事情,是将您的网络服务器占用空间减至最少。 像PHP这样的语言可以很容易地将所有东西都填充到会话存储中 - 但会话有价格标签。 如果您有多个Web服务器,则需要共享会话信息,因为它们也共享负载 - 它们中的任何一个都可能必须提供下一个请求。
共享存储是必须的。 服务器至少需要知道是否有人登录。 (如果你每次需要决定这个时都会打扰数据库,那么你几乎注定要失败。)共享存储需要比数据库快得多。 这带来了诱惑: 好吧,我有一个非常快速的存储,为什么不做那里的一切? - 而那就是事情变得令人讨厌的另一种方式。
所以你说,将会话存储保持在最低限度?
再次,这是你的决定。 你可以出于性能原因存储东西(数据库几乎总是比Redis慢),你可以冗余地存储信息,实现自己的缓存,等等 - 请记住,如果存储大量垃圾,Web服务器将有更大的负载在他们。 而且,如果他们在重负荷下(并且他们会),你会丢失有价值的信息; 使用REST思维方式,在这种情况下发生的所有事情都是客户端再次发送相同的(!)请求,并且这次会得到服务。
怎么做呢?
这里没有一个通用的解决方案。 我会说选择一个无国籍的水平并坚持下去。 会议可能会受到一些人的喜爱而被其他人讨厌,但他们不会去任何地方。 对于每个请求,尽可能多地发送尽可能多的信息; 但是不要将无国籍状态解释为没有会话,也不会每次都登录。 不知何故,服务器必须知道它是你 ; PHP会话ID是一种好方法,手动生成的令牌是另一种方法。
思考并决定,不要让设计趋势为您考虑。
这里的无状态意味着请求的状态或元数据不在服务器端维护。 通过在服务器上维护每个请求或用户的状态,将导致性能瓶颈。 只需要具有必需属性的服务器即可执行任何特定操作。
为了管理会话或为用户提供自定义体验,它需要维护一些元数据或用户可能的用户偏好状态,以及过去的请求历史记录。 这可以通过维护cookie,隐藏属性或会话对象来完成。
这可以维护或跟踪用户在应用程序中的状态。
希望这可以帮助!
开发RESTful服务时,要登录,您需要对用户进行身份验证。 可能的选择是每次打算执行用户操作时发送用户名和密码。 在这种情况下,服务器根本不会存储会话数据。
另一种选择是在服务器上生成会话ID并将其发送到客户端,因此客户端将能够将session-id发送到服务器并对其进行身份验证。 这比每次发送用户名和密码要安全得多,因为如果有人掌握了这些数据,那么他/她可以冒充用户,直到用户名和密码被更改为止。 您可能会说即使会话ID可能被盗,在这种情况下用户也会被冒充,而您是对的。 但是,在这种情况下,只有在会话ID有效时才可以模拟用户。
如果RESTful API需要用户名和密码才能更改用户名和密码,那么即使有人使用会话ID模拟用户,黑客也无法锁定真实用户。
会话ID可以通过单向锁定(加密)生成标识用户并将时间添加到会话标识的内容生成,这样就可以定义会话的到期时间。
服务器可能存储会话ID,也可能不存储会话ID。 当然,如果服务器存储会话ID,那么它将违反问题中定义的标准。 但是,确保为给定用户验证会话ID非常重要,这不需要存储会话ID。 想象一下,你有一种方式,你有一个单向加密的电子邮件,用户ID和一些用户特定的私人数据,如喜欢的颜色,这将是第一级,并以某种方式将用户名日期添加到加密的字符串,并应用两个 - 方式加密。 结果,当接收到会话id时,可以解密第二级以便能够确定用户声称的用户名以及会话时间是否正确。 如果这是有效的,则可以通过再次执行该加密并检查它是否与字符串匹配来验证第一级加密。 您无需存储会话数据即可实现此目的。