代码之家  ›  专栏  ›  技术社区  ›  Zak

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

  •  468
  • Zak  · 技术社区  · 14 年前

    我需要澄清一下。我一直在阅读有关REST的内容,并构建RESTful应用程序。根据维基百科,休息本身被定义为 表述性状态转移 . 所以我不明白这一切都是无状态的 胡说八道 每个人都在喷吐。

    维基百科:

    在任何特定时间,客户机都可以在 应用状态或“静止”。处于静止状态的客户机能够 与用户交互,但不创建负载,也不使用每个客户端 服务器集或网络上的存储。

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

    我了解到REST的一个目标是使URI访问保持一致和可用,例如,而不是在日志中隐藏分页请求,使请求的页码成为GET URI的一部分。对我来说是有意义的。但说这个似乎有点过火了 每个客户端没有数据 (会话数据)应该永远存储在服务器端。

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

    每次请求新邮件列表时,是否确实必须发送整个邮件发件人列表才能阻止?与我相关的消息列表一开始不会/不应该是一个公开可用的资源。

    再一次,试着理解这一点。某人 拜托 澄清。


    更新:

    我发现了一个堆栈溢出问题,这个问题的答案并不完全符合我的要求: How to manage state in REST 也就是说客户声明 应该 每一次请求都会被转移….嗯…好像有很多开销…这是对的吗??

    16 回复  |  直到 5 年前
        1
  •  247
  •   Wolverine fastcodejava    6 年前

    无状态意味着每个HTTP请求都是完全隔离的。当客户端发出HTTP请求时,它包含服务器完成该请求所需的所有信息。服务器从不依赖以前请求的信息。如果该信息很重要,客户机将不得不在随后的请求中再次发送它。无状态性也带来了新的特点。跨负载平衡服务器分发无状态应用程序更容易。无状态应用程序也很容易缓存。

    实际上有两种状态。驻留在客户机上的应用程序状态和驻留在服务器上的资源状态。

    Web服务只需要在您实际发出请求时关心您的应用程序状态。剩下的时间,它甚至不知道你的存在。这意味着每当客户机发出请求时,它必须包括服务器处理它所需的所有应用程序状态。

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

    希望这有助于区分无状态状态和各种状态的含义。

        2
  •  466
  •   user177800    6 年前

    基本解释是:

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

    无状态意味着 服务器 不存储有关 客户端会话 在服务器端。

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

    这并不排除Web服务器所讨论的其他服务维护业务对象(如购物车)的状态,而不排除客户机当前的应用程序/会话状态。

    这个 客户的 应用程序状态不应存储在服务器上,而是从 客户机 到每一个需要它的地方。

    这就是 装货单 在里面 休息 来自, 状态转移 . 您可以在周围传输状态,而不是让服务器存储它。 这是扩展到数百万并发用户的唯一方法。 如果不是因为其他原因,而是因为数百万次的会话是数百万次的会话。

    会话管理的负载在所有客户机之间进行分摊,客户机存储其会话状态,服务器可以以无状态方式为多个数量级或更多客户机提供服务。

    即使是你认为会的服务 只有 需要在10%的并发用户中,您仍然应该使您的服务无状态。数万人仍然是数万人,并且会有与之相关的时间和空间成本。

    无状态是HTTP协议和Web通常被设计为可操作的方式,是一种总体上更简单的实现,并且您有一个单独的代码路径,而不是一组服务器端逻辑来维护一组会话状态。

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

    这些是原则而不是实现,您如何满足这些原则可能会有所不同。

    综上所述, five key principles 是:

    1. 给每个__事物_一个ID
    2. 把事情联系在一起
    3. 使用标准方法
    4. 具有多个表示形式的资源
    5. 无状态地交流

    其余的没有关于身份验证或授权的内容 dissertation .

    因为验证一个请求和验证一个请求没有什么不同。认证与RESTful讨论无关。

    解释如何为您的特定需求创建无状态应用程序,是 太宽 用于stackoverflow。

    更重要的是,实现与REST相关的身份验证和授权 太宽 一般来说,在因特网上详细解释了各种实现方法。

    有关此问题的请求帮助/信息的评论将/应标记为 不再需要 .

        3
  •  73
  •   S.Lott    14 年前

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

    不,他们不是用一种微不足道的方式说的。

    他们说不要定义“会话”。不要登录。不要退出。在请求中提供凭据。每个请求都是独立的。

    您仍然有数据存储。您仍然具有身份验证和授权。您不需要浪费时间建立会话和维护会话状态。

    关键是,每个请求(a)完全独立,(b)可以被琐碎地传递到一个巨大的并行服务器场,而无需任何实际工作。Apache或Squid可以盲目、成功地传递RESTful请求。

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

    如果用户想要一个过滤器,那么只需在每个请求上提供过滤器。

    难道说…服务器是否只发送未被用户阻止的消息(或消息ID)?

    对。在RESTful URI请求中提供筛选器。

    每次请求新邮件列表时,是否确实必须发送整个邮件发件人列表才能阻止?

    对。这个“要阻止的邮件发件人列表”有多大?一个PK的简短列表?

    获取请求可能非常大。如果需要,您可以尝试一个POST请求,即使它听起来像一种查询。

        4
  •  34
  •   blerik Darrel Miller    10 年前

    您是完全正确的,支持与服务器的完全无状态交互确实给客户机增加了额外的负担。但是,如果考虑缩放应用程序,则客户机的计算能力与客户机的数量成正比。因此,扩展到大量客户机更为可行。

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

    这是一种权衡。

        5
  •  30
  •   Archimedes Trajano    10 年前

    用户应用程序状态管理的历史视图

    传统意义上的会话将用户的状态保存在服务器内部的应用程序中。这可能是流中的当前页,也可能是以前输入但尚未持久化到主数据库的内容。

    之所以需要这样做,是因为客户端缺乏有效地维护状态的标准,而不必使用特定于客户端(即特定于浏览器的)应用程序或插件。

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

    REST服务的一般使用

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

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

    认证

    对于任何到服务器的请求,请求的一部分应该包含授权令牌。它是如何实现的,是特定于应用程序的,但通常是 BASIC CERTIFICATE 认证形式。

    REST服务不使用基于表单的身份验证。但是,如上所述,REST服务并不打算由用户调用,而是由应用程序调用。应用程序需要管理获取身份验证令牌。在我的情况下,我用饼干 JASPIC with OAuth 2.0 to connect to Google for authentication 以及用于自动测试的简单HTTP身份验证。我也用过 HTTP Header authentication via JASPIC 对于本地测试(尽管可以在SiteMinder中执行相同的方法)

    根据这些示例,身份验证是在客户端进行管理的(尽管SiteMinder或Google会将身份验证会话存储在其端),但对于该状态没有什么可以做的,但它不是REST服务应用程序的一部分。

    检索请求

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

    事务脚本

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

    这对于REST服务[如果正确完成]意味着将单个请求发送到REST服务器将包含单个用户操作所需的所有内容,该操作执行单个事务中所需的所有内容,以及 Transaction Script 这就是所谓的模式。

    这是通过 POST 通常要求,但其他如 PUT 也可以使用。

    很多REST的人为例子(我自己做的)都试图遵循HTTP协议中定义的内容,在经历了这些之后,我决定更加务实,并将其留给 GET and POST only . 这个 方法甚至不需要实现post-redirect-get模式。

    尽管如此,正如我上面提到的,客户端应用程序将是调用服务的应用程序,它只调用 需要时(不是每次)请求所有数据。这样可以防止对服务器的持续请求。

    轮询

    尽管REST也可以用于轮询,但我不推荐使用它,除非您必须使用它,因为它与浏览器兼容。为此,我将使用我设计的WebSockets API contract 也一样。旧浏览器的另一种选择是Comet。

        6
  •  25
  •   CommaToast    8 年前

    休息很抽象。有一些好的、简单的、真实的例子是有帮助的。

    以所有主要的社交媒体应用程序为例——Tumblr、Instagram、Facebook和Twitter。它们都有一个永远滚动的视图,向下滚动的越远,看到的内容越多,时间越长。然而,我们都经历过这样的时刻:当你失去了你被滚动到的地方,应用程序会将你重置回顶部。就像如果你退出应用程序,当你重新打开它时,你又回到了顶端。

    原因是,服务器没有存储您的会话状态。遗憾的是,您的滚动位置刚刚存储在客户机的RAM中。

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

    服务器上没有登录会话,因为它们遵守REST。


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

    但是,让我们来谈谈网络浏览器,因为这带来了其他浏览器的另一个主要优势,这里没有人谈论。

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

    它不能使用他们的IP地址,因为许多人可以在共享路由器上使用相同的地址。那么,如何呢?

    它不能使用MAC地址有很多原因,尤其是因为你可以在不同的浏览器和应用程序上同时登录多个不同的Facebook帐户。一个浏览器很容易伪装成另一个,而MAC地址也同样容易被欺骗。

    如果服务器必须存储一些客户端状态来识别您,那么它必须将其存储在RAM中,而不仅仅是处理请求所需的时间,否则它必须缓存这些数据。服务器的RAM和缓存数量有限,更不用说处理器速度了。服务器端状态以指数形式增加了这三个状态。另外,如果服务器要存储关于会话的任何状态,那么它必须为您当前登录的每个浏览器和应用程序以及您使用的每个不同设备分别存储它。


    所以…我希望您现在明白为什么REST对于可伸缩性如此重要。 我希望您能够开始了解为什么服务器端会话状态是对服务器的可伸缩性,而焊接在砧板上的会话状态是对汽车加速的。


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

        7
  •  12
  •   Sam Sirry jop    8 年前

    我看到这里的基本问题是混淆了 会话 具有 状态 . 当rest指定不应存储 状态 在服务器上,没有什么可以阻止您存储用户 会话 .

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

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

    有人可能会争辩说客户机应该更好地生成令牌。我说这两种方法都有效,这取决于应用程序,以及谁将使用API。

    另外,在服务器上保留一些敏感的会话数据应该是正确的方法。您不能信任客户保留其购物车(例如)包含名为“IsFreeGift”的字段。这些信息应该保存在服务器上。

    视频链接由提供 桑塔努迪 他的回答很有帮助。如果你没有注意的话。

    只是附带说明:似乎所有已经给出的答案都忽略了这样一个事实:一些操作可能会导致服务器负载过重。这与功耗、硬件消耗和成本(对于CPU周期租用的服务器)有关。一个好的开发人员不应该懒惰地优化他们的应用程序,即使在一些租用的服务器上的现代CPU上可以很快地完成操作,而他们不需要为此支付电费和维护费用。

    尽管这个问题已经有几年了,但我希望我的回答仍然有帮助。

        8
  •  11
  •   Lightness Races in Orbit    9 年前

    无状态意味着服务的状态不会在随后的请求和响应之间持续。每个请求都带有自己的用户凭证,并分别经过身份验证。但在有状态的情况下,每个请求都是从任何先前的请求中知道的。所有有状态请求都是面向会话的,即每个请求都需要知道并保留以前请求中所做的更改。

    银行应用程序是状态应用程序的一个示例。用户首先登录,然后进行事务并注销。如果注销后,用户将尝试进行事务处理,他将无法这样做。

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

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

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

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

        9
  •  5
  •   Santanu Dey    12 年前

    看看这个演示文稿。

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

    根据这个模式-创建临时的RESTful资源来管理状态,如果需要的话。避免显式会话。

        10
  •  3
  •   psuhas    9 年前

    无状态与有状态之间的主要区别是每次都将数据传递回服务器。在无状态的情况下,客户机必须提供所有信息,因此可能需要在每个请求中传递大量参数。在有状态的情况下,cliet传递这些参数一次,并且这些参数由服务器维护,直到客户机再次修改。

    在IMO中,API应该是无状态的,这样可以快速地扩展。

        11
  •  2
  •   inf3rno    10 年前

    您必须在客户端管理客户端会话。这意味着您必须随每个请求一起发送身份验证数据,并且您可能(但不必)在服务器上有一个内存缓存,它将身份验证数据与用户信息(如标识、权限等)配对。

    这个休息 statelessness constraint 非常重要。如果不应用此约束,服务器端应用程序将不会 scale 因为维护每个客户机会话 Achilles' heel .

        12
  •  0
  •   user3857922    10 年前

    整个概念是不同的…如果您试图实现RESTful协议,则不需要管理会话。在这种情况下,最好对每个请求执行身份验证过程(而在性能方面则需要额外的成本),哈希密码就是一个很好的例子。没什么大不了的……)。如果使用会话-如何在多个服务器之间分配负载?我敢打赌,RESTful协议是为了消除任何会话——你不需要它们……这就是它被称为“无状态”的原因。只有在请求完成后无法在客户端存储cookie以外的任何内容时,才需要会话(以支持浏览器的旧的、非javascript/html5为例)。如果是“全功能”的休息客户端,通常可以安全地存储 base64(login:password) 在客户端(内存中),直到应用程序仍然被加载-应用程序被用来访问唯一的主机,cookie不能被第三方脚本破坏…

    我强烈建议对RESTful服务禁用cookie身份验证…查看基本/摘要认证-这对于基于RESTful的服务来说应该足够了。

        13
  •  0
  •   Amit    6 年前

    REST是无状态的,不维护请求之间的任何状态。客户机cookie/头被设置为像身份验证一样维护用户状态。假设客户端用户名/密码通过第三方认证机制“第二级OTP架构”等进行验证。一旦用户获得认证“头/cookies”进入到暴露的休息服务端点,我们可以假设用户为auth,因为用户带有有效的头/cookies。现在,某些像IP这样的用户信息要么保存在缓存中,然后,如果请求来自所列资源的相同IP(MAC地址),则允许用户使用。缓存被维护了一段特定的时间,一旦时间流逝,缓存就会失效。因此,可以使用缓存,也可以使用db条目来保存请求的b/w信息。

        14
  •  0
  •   dkellner    6 年前

    没有勺子。 不要认为无国籍就像“发送 全部的 你的东西一次又一次地送到服务器上”。没办法。会有状态,总是-数据库本身 毕竟是一种状态,您是注册用户,所以没有服务器端,任何一组客户端信息都是无效的。从技术上讲,你从来没有 真正的无状态。

    但是,您所能做的,以及真正有意义的,是将Web服务器的占地面积减到最小。像php这样的语言可以很容易地将所有内容都存储在会话存储中;您可以这样做,但是如果您有许多Web服务器,它们必须使用它们之间共享的内容(nfs、redis、memcached等),以便您的下一个请求知道您之前做了什么。这是因为负载平衡-您可能会在下一个请求中出现在另一个Web服务器上。虽然它们之间必须有一个共享存储(主要是因为它们必须告诉您是否登录了),但您不应该将其用作备用数据库。不是为了那个。

    所以你是说,把会话存储量降到最低?

    再说一遍,这是你的决定。由于性能原因(数据库几乎总是比Redis慢),你可以在那里存储信息,实现你自己的缓存,无论什么-记住,如果你在Web服务器上存储大量垃圾,它们将有更大的负载。而且,如果它们在重负载下断裂(它们也会断裂),您将丢失有价值的信息;按照剩余的思维方式,在这种情况下发生的所有事情都是客户发送相同的(!)再次请求,这一次就会得到服务。

    那怎么做呢?

    这里没有人适合所有的解决方案。我想说,选择一个无国籍的等级,然后继续。会议可能会被一些人喜欢,而被其他人讨厌,但他们不会去任何地方。对于每一个请求,发送尽可能多的有意义的信息,也许更多一点;但是不要将无状态性解释为没有会话,也不要解释为每次都登录。 不知怎么的,服务器肯定知道是你 ;PHP会话ID是一种好方法,手动生成的令牌是另一种。

    思考和决定,不要让设计趋势为你着想。

        15
  •  0
  •   Sourabh Bhavsar    5 年前

    这里的无状态意味着请求的状态或元数据不在服务器端维护。通过在服务器上维护每个请求或用户的状态,它将导致性能瓶颈。服务器只是被请求具有执行任何特定操作所需的属性。

    在管理会话或为用户提供自定义体验方面,它需要维护一些元数据或用户可能的偏好状态、过去的请求历史记录。这可以通过维护cookie、隐藏属性或会话对象来实现。

    这可以维护或跟踪应用程序中的用户状态。

    希望这有帮助!

        16
  •  0
  •   Lajos Arpad    5 年前

    当您开发一个RESTful服务时,为了登录,您需要对您的用户进行身份验证。一个可能的选择是在每次您打算执行用户操作时发送用户名和密码。在这种情况下,服务器根本不会存储会话数据。

    另一个选项是在服务器上生成一个会话ID并将其发送到客户机,这样客户机就能够将会话ID发送到服务器并用它进行身份验证。这比每次发送用户名和密码要安全得多,因为如果有人获得了这些数据,那么他/她可以模拟用户,直到用户名和密码被更改。您可能会说,即使会话ID也可能被盗,在这种情况下,用户也会被冒充,您是对的。但是,在这种情况下,只有会话ID有效时才能模拟用户。

    如果restful api需要用户名和密码来更改用户名和密码,那么即使有人使用会话ID模拟用户,黑客也无法锁定真正的用户。

    会话ID可以通过单向锁定(加密)标识用户并向会话ID添加时间来生成,这样就可以定义会话的到期时间。

    服务器可能存储会话ID,也可能不存储会话ID。当然,如果服务器存储会话ID,那么它将违反问题中定义的标准。但是,只有确保会话ID可以为给定的用户进行验证才是重要的,这不需要存储会话ID。设想一种方法,您可以单向加密电子邮件、用户ID和一些特定于用户的私有数据,如最喜爱的颜色,这将是第一级,并且以某种方式将用户名日期添加到e加密字符串并应用双向加密。因此,当接收到会话ID时,可以对第二级进行解密,以确定用户声明的用户名以及会话时间是否正确。如果这是有效的,那么可以通过再次进行加密并检查它是否与字符串匹配来验证第一级加密。为了实现这一点,您不需要存储会话数据。