如何在REST中管理状态

38

我猜这个问题听起来很熟悉,但我还是一名被REST搞糊涂的程序员。

我的传统web应用程序从StateA到StateB等等。 如果用户访问(StateB的)URL,我希望确保他之前已经访问了StateA。 传统上,我使用会话状态(session state)来实现这一点。

由于在REST中不允许使用会话状态(session state),那么我该如何实现这一点呢?


在你的类中使用 @Stateful。 - NaN
1个回答

54

这有两种REST答案,具体取决于你想要做什么。

如果你确实想要管理基于请求的状态(例如当用户正在通过多屏向导或其他基于导航的工作流程进行操作时),那么REST的答案是状态应该随每个请求/响应来回发送(使用类似于隐藏文本字段,查询字符串或存储在表单中的POST数据)。这是Martin Fowler的“客户端状态”设计模式的一种实现方式(在他的书《企业应用架构模式》中得到详细阐述;请参见此处获取参考资料)。

另一方面,如果你想管理服务器上的某种新对象,例如购物车,则REST的答案是你实际上正在创建一个新实体,可以像其他实体一样通过直接URL访问。无论你是否将此新实体存储在数据库中还是在应用程序内存中(如传统的Session对象)都取决于你,但是,无论哪种情况,新对象都不太涉及服务器上的“状态”,而更多地涉及为用户创建一个新实体以供交互。


5
仅有一个额外的要点。如果你采用“在服务器上新建对象”的方法,那么它应该被视为一种一级资源,并且应该拥有一个可识别的URL。 - Darrel Miller
4
我认为教条式的REST也需要为多页向导提供URL。开始向导会创建一个新资源,每个页面都会创建一个新资源,每个响应都包含一个“下一步”链接。您可以强制要求在“最终资源”之前创建所有“页面资源”;这可以通过隐式完成,使用像1/2/3/submit这样的URL。这似乎有点愚蠢,因为它正在重新创建会话状态,只是用URL。其中一个优点是,如果URL是永久链接,则会话不会超时。您可以将其加为书签以便稍后完成。 - 13ren
5
有趣的观点。 "状态"(可来回传输)和 "资源"(需指定URI)之间的分界线在哪里?是关于“具体性”,比如“一堆导航信息是一个状态,但任何看起来更像实体、容器或对象的东西都是资源”吗?还是更多地涉及生命周期或范围? - Christian Gosch
1
值得注意的是,P of EAA的“客户端状态”有其缺点:“如果客户端失败,所有数据都将丢失[...]对于大量数据而言,存储数据的位置以及每次请求传输所有数据所需的时间成本变得难以承受[...]任何发送到客户端的数据都容易被查看和篡改[...]不要假定发送出去的数据与返回的数据相同。任何返回的数据都需要完全重新验证。” - Fuhrmanator
5
@ChristianGosch 有一个我认为可以区分这两个东西的因素是会话持久性。也就是说,如果客户端出现故障(或注销),哪些数据可以被接受地丢失?那些丢失的数据将在应用程序状态中。任何希望保存以防客户端失败(或注销)的数据都必须存储在资源中。亚马逊的购物车就是一个例子。 - Fuhrmanator
显示剩余6条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接