REST删除批处理中的多个项目

问题描述 投票:4回答:2

我需要在批处理中删除id中的多个项目,但HTTP DELETE不支持正文有效负载。

解决方案:

1. @DELETE /path/abc?itemId=1&itemId=2&itemId=3 on the server side it will be parsed as List of ids and DELETE operation will be performed on each item.

2. @POST /path/abc including JSON payload containing all ids. { ids: [1, 2, 3] }

这有多糟糕,哪个选项更可取?任何替代品?

更新:请注意,性能是这里的关键,它不是每个个人ID的执行删除操作选项。

rest http-delete
2个回答
1
投票

多年来,许多人对此表示怀疑,正如我们在此处的相关问题中所看到的那样。似乎接受的答案范围从“肯定做到”到“明显错误的协议”。由于很多问题是在几年前发出的,所以让我们从2014年6月开始深入研究HTTP 1.1规范(RFC 7231),以便更好地理解明显不鼓励的内容。

The first proposed workaround:

首先,关于资源和Section 2上的URI本身:

HTTP请求的目标称为“资源”。 HTTP不限制资源的性质;它只定义了一个可能用于与资源交互的接口。每个资源由统一资源标识符(URI)标识。

基于此,有些人可能会争辩说,由于HTTP不限制资源的性质,因此包含多个id的URI是可能的。我个人认为这是一个解释问题。

关于您的第一个提议的解决方法(DELETE '/path/abc?itemId=1&itemId=2&itemId=3'),我们可以得出结论,如果您将资源视为实体集合中的单个文档,并且如果您将资源视为实体集合本身,则可以采取行动,这是不鼓励的。

The second proposed workaround:

关于你的第二个提议的解决方法(POST '/path/abc' with body: { ids: [1, 2, 3] }),使用POST方法删除可能会产生误导。关于Section 4.3.3的部分POST说:

POST方法请求目标资源根据资源自身的特定语义处理请求中包含的表示。例如,POST用于以下功能(以及其他功能):将数据块(例如输入HTML表单的字段)提供给数据处理过程;在公告栏,新闻组,邮件列表,博客或类似文章组中发布消息;创建尚未由源服务器标识的新资源;并将数据附加到资源的现有表示中。

虽然有一些空间可以解释POST的“其他”功能,但它显然与我们使用DELETE方法去除资源的事实相冲突,正如我们在Section 4.1中看到的那样:

DELETE方法删除目标资源的所有当前表示。

所以我个人强烈反对使用POST来删除资源。

An alternative workaround:

受到第二种解决方法的启发,我们建议再做一次:

DELETE '/path/abc' with body: { ids: [1, 2, 3] }

它与解决方法2中提出的几乎相同,而是使用正确的HTTP方法进行删除。在这里,我们得到了关于在body请求中使用实体DELETE的困惑。有很多人说这是无效的,但让我们坚持使用规范的Section 4.3.5

DELETE请求消息中的有效负载没有定义的语义;在DELETE请求上发送有效负载主体可能会导致某些现有实现拒绝该请求。

因此,我们可以得出结论,规范并没有阻止DELETE拥有body有效载荷。不幸的是,一些现有的实现可能会拒绝请求......但是今天这对我们有何影响?

很难100%肯定,但用fetch做出的现代要求不允许body用于GETHEAD。这就是Fetch StandardSection 5.3上陈述的第34项:

如果任一主体存在且非null或inputBody为非null,并且请求的方法为GET或HEAD,则抛出TypeError。

我们可以确认它在fetch pollyfillline 342以相同的方式实施。

Final toughts:

由于使用DELETEbody有效载荷的替代解决方案可以通过HTTP规范使用,并且得到所有现代浏览器fetch以及IE10与polyfill的支持,我推荐这种方式以有效和完整的工作方式进行批量删除。


2
投票

重要的是要理解HTTP方法在“通过网络传输文档”的域中运行,而不是在您自己的自定义域中。

您的资源模型不是您的域模型不是您的数据模型。

备选拼写:REST API是一个外观,使您的域看起来像一个网站。

在外观的后面,实现可以做它喜欢的事情,但要考虑如果实现不符合消息描述的语义,那么它(而不是客户端)对由于差异造成的任何损害负责。

DELETE /path/abc?itemId=1&itemId=2&itemId=3

因此,HTTP请求具体说明了“将删除语义应用于/path/abc?itemId=1&itemId=2&itemId=3描述的文档”。这个文档是耐用存储中三个不同项目的组合,每个项目都需要独立删除,这是一个实现细节。 REST的一部分原因是客户完全不受这种知识的影响。

但是,我觉得这是许多人迷路的地方,响应该删除请求返回的元数据告诉客户端没有关于具有不同标识符的资源。

就客户而言,/path/abc/path/abc?itemId=1&itemId=2&itemId=3的独特标识符。因此,如果客户端执行了/ path / abc的GET,并且收到了包含itemIds 1,2,3的表示;然后提交您描述的删除,它将在其自己的缓存中包含删除成功后包含/path/abc的表示。

这可能是,也可能不是你想要的。如果您正在进行REST(通过HTTP),那么您应该在设计中考虑这种事情。

POST /path/abc

some-useful-payload

此方法告诉客户端我们正在对/path/abc进行一些(可能是不安全的)更改,如果成功,则需要使之前的表示无效。客户端应重复其早期的GET /path/abc请求以刷新其先前的表示,而不是使用任何早期的无效副本。

但和以前一样,它不会影响其他资源的缓存副本

/path/abc/1
/path/abc/2
/path/abc/3

所有这些仍然会坐在缓存中,即使它们已被“删除”。

为了完全公平,很多人都不在乎,因为他们没有考虑客户端缓存他们从Web服务器获得的数据。并且您可以向Web服务器发送的响应添加元数据,以便与表示不支持缓存的客户端(和中间组件)进行通信,或者可以缓存结果,但必须在每次使用时重新验证它们。

再说一遍:您的资源模型不是您的域模型不是您的数据模型。 REST API是一种思考正在发生的事情的不同方式,并且REST架构风格经过调整以解决特定问题,因此可能不适合您尝试解决的简单问题。

这并不意味着我认为每个人都应该根据REST架构风格设计自己的系统。 REST适用于跨多个组织的基于网络的长期应用程序。如果您不认为需要约束,则不要使用它们。只要您不将结果称为REST API,那对我来说就没问题了。对于符合他们自己的建筑风格的系统我没有问题。 - Fielding, 2008

© www.soinside.com 2019 - 2024. All rights reserved.