在REST中进行交易?

rest

66676 观看

13回复

45950 作者的声誉

我想知道您如何在REST中实现以下用例。是否有可能在不损害概念模型的情况下做?

在单个事务范围内读取或更新多个资源。例如,将$ 100从Bob的银行帐户转入John的帐户。

据我所知,实现这一目标的唯一方法是作弊。您可以发布到与John或Bob关联的资源,并使用单个事务执行整个操作。就我而言,这破坏了REST架构,因为您实际上是通过POST来传送RPC调用的通道,而不是真正在单个资源上进行操作。

作者: Gili 的来源 发布者: 2008 年 9 月 29 日

回应 (13)


9

26613 作者的声誉

您必须推出自己的“交易ID”类型的TX管理。因此,将有4个调用:

http://service/transaction (some sort of tx request)
http://service/bankaccount/bob (give tx id)
http://service/bankaccount/john (give tx id)
http://service/transaction (request to commit)

您必须处理动作存储在数据库(如果负载平衡)或内存等中,然后处理提交,回滚,超时。

在公园里并不是一个令人愉快的一天。

作者: TheSoftwareJedi 发布者: 29.09.2008 01:52

-3

20515 作者的声誉

我想您可以在网址/资源中包含TAN:

  1. 进行交易/交易以获取ID(例如“ 1”)
  2. [PUT,GET,POST,等等] / 1 / account / bob
  3. [PUT,GET,POST,等等] / 1 /帐户/帐单
  4. ID为1的删除/交易

只是一个主意。

作者: Till 发布者: 29.09.2008 02:01

87

118929 作者的声誉

决定

考虑一个RESTful购物篮方案。从概念上讲,购物篮是您的事务包装器。您可以将多个项目添加到购物篮中,然后提交该购物篮来处理订单,方法与您可以将Bob的帐户条目添加到事务包装器中,然后将Bill的帐户条目添加到包装器中的方式相同。当所有部件都放置到位后,您可以将所有组件部件进行POST / PUT事务包装。

作者: Darrel Miller 发布者: 29.09.2008 02:13

2

29066 作者的声誉

我认为在这种情况下打破REST的纯理论是完全可以接受的。无论如何,我认为REST中实际上没有任何内容表明您无法在需要它的业务案例中接触依赖对象。

我真的认为,当您只需要利用数据库来执行此操作时,创建一个自定义事务管理器就不会花额外的钱。

作者: Toby Hede 发布者: 29.09.2008 02:35

0

381 作者的声誉

在简单的情况下(没有分布式资源),您可以将事务视为资源,创建事务的行为可以达到最终目标。

因此,要在<url-base>/account/a和之间转移<url-base>/account/b,您可以将以下内容发布到<url-base>/transfer

<转移>
      / account / a 
      / account / b 
     50 

这将创建一个新的传输资源并返回该传输的新url-例如<url-base>/transfer/256

然后,在成功过账的那一刻,“真实”交易在服务器上进行,并且金额从一个帐户中删除并添加到另一个帐户中。

但是,这不包括分布式交易(如果说“ a”存放在一项服务后面的一家银行,而“ b”存放在另一项服务后面的另一家银行)–除了说“尝试用全部措词以不需要分布式交易的方式进行操作”。

作者: Phasmal 发布者: 08.10.2010 03:37

56

3947 作者的声誉

有几个重要的问题没有被这个问题回答,我认为这太糟糕了,因为它在Google的搜索词中排名很高:-)

具体来说,一个不错的选择是:如果您两次发布(由于中间缓存被某些缓存损坏),则您不应将其转移两次。

为此,您将事务创建为对象。这可能包含您已经知道的所有数据,并将事务置于挂起状态。

POST /transfer/txn
{"source":"john's account", "destination":"bob's account", "amount":10}

{"id":"/transfer/txn/12345", "state":"pending", "source":...}

有了该事务后,就可以提交它,例如:

PUT /transfer/txn/12345
{"id":"/transfer/txn/12345", "state":"committed", ...}

{"id":"/transfer/txn/12345", "state":"committed", ...}

注意,在这一点上,多次看跌并不重要。甚至在txn上的GET都将返回当前状态。具体来说,第二个PUT会检测到第一个PUT已经处于适当的状态,然后将其返回-或者,如果在它已经处于“提交”状态后尝试将其置于“回滚”状态,则会得到一个错误,并将实际的已提交事务退回。

只要您与单个数据库或具有集成事务监视器的数据库进行对话,该机制实际上就可以正常工作。您可能还会引入事务超时,如果您愿意,甚至可以使用Expires标头表示。

作者: Jon Watte 发布者: 19.01.2011 10:46

31

327 作者的声誉

用REST术语来说,资源是可以与CRUD(创建/读取/更新/删除)动词配合使用的名词。由于没有“转移资金”动词,因此我们需要定义一个可以使用CRUD进行操作的“交易”资源。这是HTTP + POX中的示例。第一步是创建(HTTP POST方法)一个新的事务:

POST /transaction

这将返回交易ID,例如“ 1234”,并返回URL“ / transaction / 1234”。请注意,多次触发此POST不会创建具有多个ID的同一事务,并且还避免引入“待处理”状态。另外,POST不一定总是幂等的(REST要求),因此通常最好的做法是最小化POST中的数据。

您可以将事务ID的生成留给客户。在这种情况下,您将发布/ transaction / 1234来创建事务“ 1234”,并且服务器将返回错误(如果已经存在)。在错误响应中,服务器可以返回带有适当URL的当前未使用的ID。用GET方法向服务器查询新的ID并不是一个好主意,因为GET绝不应更改服务器状态,而创建/保留新的ID会更改服务器状态。

接下来,我们使用所有数据更新(PUT HTTP方法)事务,隐式提交:

PUT /transaction/1234
<transaction>
  <from>/account/john</from>
  <to>/account/bob</to>
  <amount>100</amount>
</transaction>

如果之前已对ID为“ 1234”的事务进行了PUT,则服务器将给出错误响应,否则将给出OK响应以及用于查看已完成事务的URL。

注意:在/ account / john中,“ john”应该确实是John的唯一帐号。

作者: Tuckster 发布者: 03.04.2011 11:56

19

6801 作者的声誉

很好的问题,REST主要通过类似于数据库的示例进行解释,其中存储,更新,检索,删除了某些内容。很少有这样的示例,其中服务器应该以某种方式处理数据。我认为罗伊·菲尔丁(Roy Fielding)毕竟没有以http为基础的论文。

但是他确实谈到了“代表性状态转移”作为状态机,并将链接移至下一个状态。这样,文档(表示形式)就可以跟踪客户端状态,而不必由服务器来执行。这样,就没有客户端状态,只有关于您所处链接的状态。

我一直在考虑这个问题,在我看来,让服务器为您处理某些事情是合理的,当您上传时,服务器会自动创建相关资源,并为您提供链接到它们的资源(实际上,无需自动创建它们:它可以告诉您链接,并且仅当您关注它们时才创建它们-惰性创建)。并为您提供创建新的相关资源的链接-相关资源具有相同的URI,但更长(添加后缀)。例如:

  1. 您将所有信息上载(POST交易概念的表示形式 这看起来就像一个RPC调用,但实际上是在创建“建议的事务资源”。例如URI:/transaction 毛刺将导致创建多个此类资源,每个资源都有不同的URI。
  2. 服务器的响应说明了创建的资源的URI,它的表示形式-包括用于创建新的“承诺的交易资源”的相关资源的链接(URI其他相关资源是删除建议的交易的链接。这些是状态机中客户端可以遵循的状态。从逻辑上讲,这些是服务器上已创建的资源的一部分,超出了客户端提供的信息。如的URI: /transaction/1234/proposed/transaction/1234/committed
  3. 您将POST到链接以创建“承诺的交易资源”,该资源创建该资源,从而更改服务器的状态(两个帐户的余额)**。从本质上讲,该资源只能创建一次,并且无法更新。因此,不会发生提交许多事务的故障。
  4. 您可以获取这两个资源,以查看它们的状态。假设POST可以更改其他资源,则该提案现在将标记为“已提交”(或者可能根本不可用)。

这类似于网页的操作方式,最终网页上显示“您确定要这样做吗?”。最终的网页本身就是交易状态的表示,其中包括指向下一个状态的链接。不只是金融交易;也(例如)预览然后提交到维基百科。我猜想REST中的区别是状态序列中的每个阶段都有一个明确的名称(它的URI)。

在现实生活中的交易/销售中,对于交易的不同阶段(提案,采购订单,收据等),通常会有不同的物理文件。甚至更多用于购房,定居等。

OTOH感觉就像在玩语义学。我不喜欢将动词转换成名词以使其具有RESTful的名义,“因为它使用名词(URI)而不是动词(RPC调用)”。即名词“ committed transaction resource”而不是动词“ commit this transaction”。我猜想名词化的一个优点是您可以按名称引用资源,而不需要以其他方式指定资源(例如维护会话状态,因此您知道“此”交易是...)。

但是重要的问题是:这种方法的好处是什么?即,这种REST风格比RPC风格更好?除存储/检索/更新/删除之外,一种适用于网页的技术还有助于处理信息吗?我认为REST的主要好处是可伸缩性。一方面不需要显式维护客户端状态(而是将其隐式包含在资源的URI中,然后将下一个状态作为其表示形式的链接)。从这个意义上讲,它有所帮助。也许这也有助于分层/流水线工作?OTOH只有一个用户可以查看他们的特定交易,因此缓存它没有优势,因此其他人可以读取它,这对http来说是一个巨大的胜利。

作者: 13ren 发布者: 14.12.2011 04:33

1

2007 作者的声誉

您不得在REST中使用服务器端事务。

REST约束之一:

无状态

客户端与服务器之间的通信受到请求之间没有存储在服务器上的客户端上下文的进一步限制。来自任何客户端的每个请求都包含服务该请求所需的所有信息,并且任何会话状态都保留在客户端中。

唯一的RESTful方法是创建事务重做日志并将其置于客户端状态。客户端根据请求发送重做日志,服务器重做事务,然后

  1. 回滚事务,但提供新的事务重做日志(更进一步)
  2. 或最终完成交易。

但是使用基于服务器会话的技术可能更简单,该技术支持服务器端事务。

作者: bebbo 发布者: 05.07.2013 08:58

11

111 作者的声誉

如果您退一步来总结这里的讨论,那么很显然REST不适合许多API,尤其是当客户机/服务器交互本质上是有状态的时,尤其是在非平凡事务中。为什么要为客户端和服务器都跳过建议的所有步骤,以认真地遵循一些不适合该问题的原则?更好的原则是为客户提供最简单,最自然,高效的方式来编写应用程序。

总而言之,如果您确实在应用程序中执行大量事务(类型,而不是实例),则实际上不应该创建RESTful API。

作者: Peris 发布者: 09.03.2014 03:57

1

13 作者的声誉

我相信使用客户机上生成的唯一标识符来确保连接中断不会暗示API保存了双重性的情况。

我认为,将客户生成的GUID字段与转账对象一起使用,并确保不再再次插入相同的GUID,这将是解决银行转账事宜的更简单解决方案。

不知道更复杂的情况,例如多张机票预订或微型架构。

我找到了一篇有关该主题的论文,其中涉及在RESTful服务处理事务原子性的经验。

作者: Eduardo Rolim 发布者: 26.03.2015 07:22

3

3129 作者的声誉

首先,转移资金是您在单个资源调用中无法做到的。您要执行的操作是汇款。因此,您将汇款资源添加到发送者的帐户中。

POST: accounts/alice, new Transfer {target:"BOB", abmount:100, currency:"CHF"}.

做完了 您不需要知道这是必须是原子性的交易。您只需重新汇款即可。从A到B汇款。


但在极少数情况下,这里是一个通用解决方案:

如果您想做一个非常复杂的事情,需要在定义的上下文中使用许多资源,并且实际上要跨越什么障碍与为什么障碍(业务与实施知识)之间有很多限制,那么您就需要转移状态。由于REST应该是无状态的,因此作为客户端,您需要转移状态。

如果您转移状态,则需要向客户端隐藏内部信息。客户不应只知道实施所需的内部信息,而不能携带与业务相关的信息。如果这些信息没有商业价值,则应加密状态,并需要使用诸如令牌,通行证之类的隐喻。

这样,人们就可以传递内部状态,并且使用加密和签名系统仍然可以安全可靠。为客户找到正确的抽象,为什么他会传递状态信息,这取决于设计和体系结构。


真正的解决方案:

请记住,REST是在谈论HTTP,而HTTP附带了使用cookie的概念。当人们谈论REST API和跨越多个资源或请求的工作流以及交互时,这些cookie通常会被忘记。

记住维基百科上关于HTTP cookie的内容:

Cookies被设计为一种可靠的机制,使网站可以记住状态信息(例如购物车中的物品)或记录用户的浏览活动(包括单击特定按钮,登录或记录用户迄今为止访问过的页面)追溯到几个月或几年前)。

因此,基本上,如果您需要传递状态,请使用Cookie。出于完全相同的原因设计它,它是HTTP,因此通过设计它与REST兼容:)。


更好的解决方案:

如果您谈论的是客户端执行涉及多个请求的工作流,那么您通常会谈论协议。每种协议的形式都为每个可能的步骤提供了一组前提条件,例如在可以执行B之前执行步骤A。

这很自然,但是将协议暴露给客户端会使一切变得更加复杂。为了避免这种情况,只要想一想当我们必须在现实世界中进行复杂的交互和事物时该怎么做...。我们使用代理。

使用代理程序隐喻,您可以提供一种资源,该资源可以为您执行所有必需的步骤,并将正在执行的实际任务/指令存储在其列表中(这样我们就可以在代理程序或“代理机构”上使用POST)。

一个复杂的例子:

买房子:

您需要证明您的信誉(例如提供您的警察记录条目),需要确保财务细节,需要使用律师和存储资金的受信任第三方购买实际房屋,并确认房屋现在属于您,并且将购买的商品添加到您的税收记录等中(例如,某些步骤可能是错误的或其他原因)。

这些步骤可能需要几天的时间才能完成,有些可以并行完成,等等。

为了做到这一点,您只需给代理商任务买房,例如:

POST: agency.com/ { task: "buy house", target:"link:toHouse", credibilities:"IamMe"}.

做完了 代理商会将您的参考发回给您,您可以使用该参考来查看和跟踪此工作的状态,其余的则由代理商的代理商自动完成。

例如,考虑一个错误跟踪器。基本上,您报告错误,并可以使用错误ID来检查发生了什么。您甚至可以使用服务来监听此资源的更改。任务完成。

作者: Martin Kersten 发布者: 19.10.2015 09:22

10

13515 作者的声誉

我离开这个话题已经有十年了。回来时,我不敢相信当您Google休息+可靠时,您会迷恋作为科学的宗教。混乱是神话。

我将这个广泛的问题分为三个部分:

  • 下游服务。您开发的任何Web服务都将具有您使用的下游服务,并且您必须遵循其事务语法。您应该尝试对服务的用户隐藏所有这些内容,并确保操作的所有部分作为一个组成功或失败,然后将此结果返回给用户。
  • 您的服务。客户希望Web服务调用的结果清晰无误,而通常直接在实质性资源上进行POST,PUT或DELETE请求的REST模式让我感到不满意,并且很容易改善这种确定性的方式。如果您关心可靠性,则需要确定操作请求。该ID可以是在客户端上创建的GUID,也可以是服务器上关系DB的种子值,这无关紧要。对于服务器生成的ID,请使用“预检”请求-响应来交换操作的ID。如果此请求失败或成功一半,则没问题,客户端将重复该请求。未使用的ID无害。

    这很重要,因为它可以使所有后续请求完全等幂,从某种意义上说,如果将它们重复n次,它们将返回相同的结果,并且不会导致进一步的发生。服务器存储针对操作ID的所有响应,并且如果看到相同的请求,则会重播相同的响应。此Google文档对此模式进行了更全面的介绍。该文档提出了一个我相信(!)大致遵循REST原则的实现。专家们一定会告诉我它是如何侵犯他人的。无论是否涉及下游事务,此模式都可用于对您的Web服务进行任何不安全的调用。
  • 将您的服务集成到由上游服务控制的“交易”中。在Web服务的上下文中,完全ACID交易通常被认为是不值得的,但是您可以通过在确认响应中提供取消和/或确认链接来极大地帮助您的服务使用者,从而通过补偿实现交易

您的要求是基本要求。不要让别人告诉您您的解决方案不是犹太洁食。根据解决您的问题的能力和简便程度来判断他们的体系结构。

作者: bbsimonbb 发布者: 15.02.2016 09:35
32x32