REST 购物车
Posted
技术标签:
【中文标题】REST 购物车【英文标题】:REST Shopping cart 【发布时间】:2016-02-20 13:32:35 【问题描述】:可以使用 REST 架构约束来实现购物车吗?
我想把我的问题集中在会话状态上。在实现购物车的典型 MVC 应用程序中,会话对象很可能会在会话中进行管理,购物车作为产品列表。
如果应用程序遵循 REST 架构,将如何管理相同的购物车。 REST 约束之一是状态管理是客户端的责任。
是否应该由客户管理购物车及其进度?有什么例子吗?对于简单的购物车或任何其他企业应用程序,在客户端管理状态有什么缺点吗?
【问题讨论】:
你应该看看事实上的 Hello World of REST(RestBucks 咖啡店)。 您将 HTTP 术语意义上的会话状态与作为服务器端框架提供的工件的“会话”全局对象混为一谈。 我想澄清一下...购物车,当然会在购物完成后保存到数据库中,问题不是那么基本。我的问题是关于无状态通信的第四个 REST 约束,或者换句话说,服务器上没有存储客户端会话数据。鉴于此,购物车将在哪里成为商店客户?这个问题在下面的答案中得到了澄清。谢谢。 @SatBobbi 客户端在任何时候都不会存储有关购物车的任何信息。与购物车相关的所有信息都将存储在服务器中。 @CassioMazzochiMolin,问题是关于,在用户完成购物之前,您将在哪里管理“购物车”,因为它可以跨越从用户完成购物前半小时到一个小时的任何地方,最后提交购物车。用户在此期间向此购物车添加/删除产品。问题不在于您最终将在哪里保留购物车。您可能还没有理解我的问题,可能在下面给出了答案。我认为这个问题得到了回答,没有足够的声誉来提高答案。 【参考方案1】:在 REST 应用程序中,会话状态完全由客户端管理,请求必须包含服务器能够理解的所有必要信息。例如,如果服务器需要身份验证,则每个请求都必须包含凭据。
REST stateless constraint 定义如下:
5.1.3 无状态
[...] 从客户端到服务器的每个请求都必须包含理解请求所需的所有信息,并且不能利用服务器上存储的任何上下文。因此,会话状态完全保留在客户端上。 [...]
但是,无状态约束并不意味着服务器不应该存储任何数据。
在 会话状态 由服务器管理的应用程序中,将购物车数据存储在 HTTP 会话中是一种常见的方法。但是购物车不是会话状态。而且,它可能不应该完全由客户管理。
在 REST 中,购物车可以是由 URL 标识的资源,例如 /shopping-cart
,并且可以对其执行操作。所有购物车数据都可以保存到服务器上的数据库中。
Any information that can be named can be a REST resource,甚至是购物车:
5.2.1.1 资源和资源标识符
REST 中信息的关键抽象是资源。任何可以命名的信息都可以是资源:文档或图像、时间服务(例如“洛杉矶今天的天气”)、其他资源的集合、非虚拟对象(例如人)等等.换句话说,任何可能成为作者超文本参考目标的概念都必须符合资源的定义。资源是到一组实体的概念映射,而不是在任何特定时间点对应于映射的实体。 [...]
您可以在您的购物车上执行如下操作:
GET /shopping-cart
:拿到购物车。
POST /shopping-cart
:将商品添加到购物车(发送一些数据以及您要添加的商品和请求正文中的金额)。
DELETE /shopping-cart/1
:从购物车中删除 id 为 1
的商品。
PATCH /shopping-cart
:更新购物车(在请求正文中发送一些要更新的数据)。
PUT /shopping-cart
:替换购物车的全部内容(在请求正文中用您的购物车内容发送一些数据)。
DELETE /shopping-cart
:移除购物车
POST /shopping-cart/order
:订购购物车内容
因此,请注意客户端不会随时存储有关购物车的任何信息。与购物车相关的所有信息都将存储在服务器中。
有关 REST 的更多信息,我建议您阅读 Roy T. Fielding 的 dissertation 的 chapter 5。
【讨论】:
用户可以花30分钟购物,然后提交购物车,看到总价,可能决定从购物车中删除一些产品,然后再次提交,购物车在哪里在这样的客户端服务器交互中管理,在客户端代码中?还是根据您的上述解释将其持久化到数据库中。 @SatBobbi 所有的购物车数据都会被持久化到服务器的数据库中。 感谢您的回复。我不同意......如果我们在数据库中保存状态,它会破坏约束的目的。我认为,我们不需要购物车的 REST 应用程序,任何其他 Web 应用程序都可以解决设计问题。我正在寻找一个示例,如果状态在客户端中完全管理,或者在客户端中完全管理状态可能会出现什么问题。 @SatBobbi 看看我更新的答案。在 REST 中,stateless 意味着 session state 由客户端管理,每个请求都必须携带所有必要的信息才能完成。 Mazzochi Molin,感谢您的回复。问题不在于最终保留信息。问题是关于寻找,如果购物车将在客户端存储和管理,直到操作完成。它是。谢谢。【参考方案2】:存在很多关于 REST 的困惑,因为很多人听说过 REST 约束,并认为它们是无缘无故应用的规则,除了遵循架构本身。
您应该问的真正问题是,为什么 REST 中存在无状态约束,以及遵循它可以获得哪些优势。请记住,REST 是一种用于大规模分布式系统长期演进的架构风格。在单个数据库保存您的所有信息的小型应用程序中,您根本不会遇到 REST 应该解决的问题。
无状态约束引入可见性, 可靠性和可扩展性。能见度提高 因为监控系统不必超越单个 请求数据以确定请求的全部性质。 可靠性得到了提高,因为它简化了从 部分失败。可扩展性得到改进,因为不必 在请求之间存储状态允许服务器组件快速 免费资源,并进一步简化实施,因为 服务器不必跨请求管理资源使用情况。
因此,无状态意味着客户端请求应具有处理它所需的所有信息。
知名度对您来说有多重要?您是否希望在调试某些东西时能够从客户端请求中看到购物车的全部内容,或者您是否可以从数据库中获取该信息?
可靠性有多重要?您是否有一个包含多个服务器和数据库的大型分布式系统,这在哪里很重要?如果您有一个大型分布式系统,其中购物车信息可能存储在不同的数据库中,具体取决于响应请求的确切 HTTP 服务器,如果服务器出现故障,则只有该组中的另一台服务器能够满足请求并完成会话,否则来自另一个组的服务器将强制客户端重新启动会话。如果所有信息都包含在请求中,那么任何服务器都可以做到。
可扩展性有多重要?如果您有一个分布式系统,并且您将购物车信息存储在单个数据库中,它就会成为您所有请求的漏斗,并且您会失去可伸缩性。如果您将其存储在多个数据库中,则会失去如上所述的可靠性。
那么,您是否有雄心勃勃的长期目标,或者您的应用程序是否足够大,以至于您将面临 REST 试图解决的问题?如果你总是有几台服务器和一个数据库,并且你会为每个请求使用它,那么你是否成为无状态并不重要。你可以只拥有一个/shopping_cart
资源或类似的东西,通过POST
请求向其中添加内容,完成后关闭或删除它。
如果您要将数据分片到多个数据库、大量响应请求的 HTTP 服务器、缓存服务器等,并且您希望能够通过根据需要设置新服务器并删除它们来动态配置容量当负载减少时,它们会完全无状态,并将购物车留给客户端。
【讨论】:
谢谢!在问之前我知道,这个约束解决了可扩展性,所以同样的约束解决了可靠性和可见性!所以我喜欢将状态留给客户端,因为设想的应用程序是大规模分布式应用程序。我想问这个后续问题,按照我正在阅读的内容,REST 的 HTTP 实现引入了“消息级安全性和分布式事务”的缺点。鉴于您如何证明您在“请记住 REST 是一种旨在长期发展大规模分布式系统的架构风格”上面的评论。【参考方案3】:将购物车作为资源存储在服务器上没有任何问题。 会话状态应该存储在客户端上。 https://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm#sec_5_1_3
为了无状态,您的购物车 URI 应该能够识别唯一的购物车,而无需依赖任何会话信息。
例如,/shopping-cart
可能不够,除非您的应用程序中只有一个购物车。
可能,每位用户至少会有一辆购物车。因此,您可以使用 /user/1234/shopping-cart
或 /shopping-cart?userID=1234
之类的东西。
更有可能的是,您可能需要每个用户拥有多个购物车。因此,您需要为您的购物车提供一个唯一 ID,例如 /user/1234/shopping-cart/5678
或只是 /shopping-cart/5678
。
关键是,处理请求所需的一切都应该在请求中。
【讨论】:
谢谢,是的,让购物车成为服务器上的可寻址资源是有意义的,很可能是 /purchase-order/shopping-cart 我不知道为什么有人反对这个。这是迄今为止IMO最准确的答案。永远不要忘记 REST 描述的是 Web 空间中发生的事情,而不是应用程序领域中发生的事情。 我同意你关于服务器上购物车寻址能力的回答,将状态留在客户端。没有足够的声誉来提高你的答案。谢谢回答。不确定您所说的“REST 描述了 Web 空间中发生的事情,而不是应用程序领域中发生的事情”。谢谢。 如果我想在我的网页中支持匿名用户怎么办?我希望他们能够添加一些项目并结帐。在这种情况下,用户 ID 是什么? 在这种情况下,您可能不需要用户 ID。我会选择/shopping-cart/5678
。或者您可以生成仅用于会话的用户 ID。或者您可以使用 /user/anon/shopping-cart/5678
之类的占位符。【参考方案4】:
是的,你可以,
购物车数据(添加的产品)可以保存在客户端会话中,这不是问题。
然后一旦用户点击 /checkout,购物车应该被持久化在服务器上的数据库中。休息的关键是客户提出的每个请求都必须包含所有数据以识别自己,我建议阅读有关 JWT 或 OAuth 的内容。
该应用程序本身可以像您看到的任何其他购物车应用程序一样工作,其中大多数不会将购物车保存在数据库中,只需将其存储在客户端会话中。
【讨论】:
【参考方案5】:我认为有人为 STATELESS 概念选择了非常不幸的名称,这就是造成整个误解的原因。这不是关于存储任何类型的资源,而是关于客户端和服务器之间的关系。
客户:我给你发“任务清单”,需要处理。做好你的工作。
服务器:好吧..让我负责处理对您很重要的数据,以便给您正确的响应。
意思是,服务器是客户端的“奴隶”,每次请求后都必须忘记他的“主人”。
【讨论】:
【参考方案6】:我认为这就是 SPA(单页应用程序)开始使用的地方,因为 SPA 会立即加载,之后变量会保持状态,并且如果组件是分层的,您可以在组件之间传递它们,否则您也可以使用存储(如 Redux)来维护状态。
但是我觉得理想情况下,您希望在以下情况下为用户保留购物车: 1)用户将商品添加到购物车但没有订购。稍后,也许第二天他想从他离开的地方继续。所以应该坚持下去 2)用户从多个设备登录,比如多个家庭成员使用同一个帐户。在这里,购物车也应该是同步的。
【讨论】:
以上是关于REST 购物车的主要内容,如果未能解决你的问题,请参考以下文章