ChatGPT解决这个技术问题 Extra ChatGPT

删除一堆项目的宁静方式

wiki article for REST 中表明如果您使用 http://example.com/resources DELETE,这意味着您正在删除整个集合。

如果您使用 http://example.com/resources/7HOU57Y DELETE,则表示您正在删除该元素。

我正在做一个网站,注意不是网络服务。

我有一个列表,列表中的每个项目都有 1 个复选框。一旦我选择了多个要删除的项目,我将允许用户按下一个名为 DELETE SELECTION 的按钮。如果用户按下按钮,会弹出一个 js 对话框,要求用户确认删除。如果用户确认,则删除所有项目。

那么我应该如何以 RESTFUL 方式删除多个项目呢?

注意,目前对于网页中的 DELETE,我所做的是我使用 FORM 标记和 POST 作为操作,但包含一个自 this is what was indicated by others in SO on how to do RESTful delete for webpage 以来值为 DELETE 的 _method。

以原子方式执行这些删除是否至关重要?如果无法删除第 31 项,您是否真的要反转删除前 30 项?
@darrelmiller 好问题。我认为如果删除是原子执行的,效率会降低。因此,我倾向于从表名 WHERE ID IN ({list of ids}) 中删除。如果有人可以向我指出这是一个好主意还是纠正我。那将不胜感激。如果第 21 项被删除,我也不需要前 20 项的反向删除。如果有人可以向我展示我需要反转的方法与我不需要反转的方法的区别,我再次感谢
注意:“IN”子句可能有限制;例如,在 Oracle 中,您最多可以放置 1000 个 id。
Google 的 API 设计指南提供了一种在 REST API 中创建自定义(批处理)操作的解决方案,请在此处查看我的答案:stackoverflow.com/a/53264372/2477619

r
rojoca

一种选择是创建删除“事务”。因此,您 POSThttp://example.com/resources/deletes 一个新资源,其中包含要删除的资源列表。然后在您的应用程序中,您只需执行删除。当您发帖时,您应该返回您创建的交易的位置,例如 http://example.com/resources/deletes/DF4XY7。对此的 GET 可以返回事务的状态(完成或正在进行)和/或要删除的资源列表。


与您的数据库无关。事务我只是指要执行的操作列表。在这种情况下,它是一个删除列表。您所做的是在应用程序中创建一个新列表(删除列表)作为资源。您的 Web 应用程序可以根据需要处理该列表。该资源有一个URI,例如example.com/resources/deletes/DF4XY7。这意味着您可以通过对该 URI 的 GET 来检查删除的状态。如果您在删除时必须从 Amazon S3 或其他一些 CDN 中删除图像并且该操作可能需要很长时间才能完成,这将非常方便。
+1 这是一个很好的解决方案。 @rojoca 建议创建一种新型资源的实例,其唯一任务是删除资源列表,而不是向每个资源发送 DELETE。例如,您有一个用户资源集合,并且您想从集合中删除用户 Bob、Dave 和 Amy,因此您创建了一个新的删除资源,将 Bob、Dave 和 Amy 发布为创建参数。创建删除资源,并表示从用户集合中删除 Bob、Dave 和 Amy 的异步过程。
对不起。我在理解一些问题上仍然有些困难。 DF4XY7。你到底是怎么生成这个字符串的?此删除资源。我需要在数据库中插入任何数据吗?如果我重复一些问题,我深表歉意。这对我来说有点陌生。
我假设 DF4XY7 是生成的唯一 id,也许只使用保存到数据库时生成的 id 更自然,例如 example.com/resources/deletes/7。我的想法是创建删除模型并将其保存在数据库中,您可以让异步过程删除其他记录以完成状态和任何相关错误更新删除模型。
@rojoca 是的,我认为问题在于 HTTP 非常“删除用于删除单个资源”。无论您做什么,多次删除都有点麻烦。您仍然可以向客户端返回一个“工作”,说明此任务正在处理(可能需要一些时间),但使用此 URI 来检查进度。我阅读了规范并认为 DELETE 可以有一个主体,就像其他请求一样。
J
Jonnny

我认为 rojoca's answer 是迄今为止最好的。一个轻微的变化可能是,取消同一页面上的 javascript 确认,而是创建选择并重定向到它,在该页面上显示确认消息。换句话说:

来自:
http://example.com/resources/

做一个

使用选择的 ID 发布到:
http://example.com/resources/selections

如果成功,应回复:

已创建 HTTP/1.1 201,并将 Location 标头发送到:
http://example.com/resources/selections/DF4XY7

然后,在此页面上,您将看到一个(javascript)确认框,如果您确认,它将执行以下请求:

删除 http://example.com/resources/selections/DF4XY7

如果成功,应该响应:HTTP/1.1 200 Ok(或任何适合成功删除的内容)


我喜欢这个想法,因为您不需要任何重定向。结合 AJAX,您可以在不离开页面的情况下完成这一切。
在此 DELETE example.com/resources/selections/DF4XY7 之后,我会被重定向回 example.com/resources 吗?
@fireeyeboy 这种两步方法似乎是执行多重删除的常用建议方式,但为什么呢?为什么不简单地向 http://example.com/resources/selections/ 之类的 uri 发送 DELETE 请求,并在请求的有效负载(正文)中发送要删除的项目的数据。据我所知,没有什么能阻止你这样做,但我总是遇到“但它不是 RESTfull”。
DELETE 可能会使正文被 HTTP 基础结构忽略:stackoverflow.com/questions/299628/…
DELETE 可以有一个主体,但是它的很多实现默认禁止它的主体
L
Luka Žitnik

以下是 Amazon 使用他们的 S3 REST API 所做的事情。

个人删除请求:

DELETE /ObjectName HTTP/1.1
Host: BucketName.s3.amazonaws.com
Date: date
Content-Length: length
Authorization: authorization string (see Authenticating Requests (AWS Signature Version 4))

Multi-Object Delete 请求:

POST /?delete HTTP/1.1
Host: bucketname.s3.amazonaws.com
Authorization: authorization string
Content-Length: Size
Content-MD5: MD5

<?xml version="1.0" encoding="UTF-8"?>
<Delete>
    <Quiet>true</Quiet>
    <Object>
         <Key>Key</Key>
         <VersionId>VersionId</VersionId>
    </Object>
    <Object>
         <Key>Key</Key>
    </Object>
    ...
</Delete>           

但是 Facebook Graph APIParse Server REST APIGoogle Drive REST API 更进一步,使您能够在一个请求中“批处理”单个操作。

这是 Parse Server 的一个示例。

个人删除请求:

curl -X DELETE \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  https://api.parse.com/1/classes/GameScore/Ed1nuqPvcm

批量请求:

curl -X POST \
  -H "X-Parse-Application-Id: ${APPLICATION_ID}" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
        "requests": [
          {
            "method": "POST",
            "path": "/1/classes/GameScore",
            "body": {
              "score": 1337,
              "playerName": "Sean Plott"
            }
          },
          {
            "method": "POST",
            "path": "/1/classes/GameScore",
            "body": {
              "score": 1338,
              "playerName": "ZeroCool"
            }
          }
        ]
      }' \
  https://api.parse.com/1/batch

f
fezfox

有趣的是,我认为相同的方法适用于修补多个实体,并且需要考虑我们对 URL、参数和 REST 方法的含义。

返回所有“foo”元素:[GET] api/foo 返回“foo”元素,过滤特定 id:[GET] api/foo?ids=3,5,9

其中的意义是 URL 和过滤器确定“我们正在处理哪些元素?”,而 REST 方法(在本例中为“GET”)表示“如何处理这些元素?”

因此 PATCH 多个记录以将它们标记为已读 [PATCH] api/foo?ids=3,5,9

..数据 foo[read]=1

最后要删除多条记录,这个端点最符合逻辑:[DELETE] api/foo?ids=3,5,9

请理解我不相信这有任何“规则”——对我来说这只是“有意义”


实际上关于PATCH:因为如果您将实体列表视为实体本身(即使是数组类型),它意味着部分更新,发送部分实体的部分数组(仅您想要更新的ID),那么您可以省略查询字符串,因此没有代表多个实体的 URL。
确实,只是简单的解决方案。为什么人们必须坚持让自己变得困难,有时我无法理解。
s
sashoalm

我会说 DELETE http://example.com/resources/id1,id2,id3,id4 或 DELETE http://example.com/resources/id1+id2+id3+id4。由于“REST 是一种架构(...)[不是]协议”引用这篇维基百科文章,我相信没有单一的方法可以做到这一点。

我知道如果没有带有 HTML 的 JS,以上是不可能的,但我觉得 REST 是:

创建时不考虑交易等次要细节。谁需要对单个项目进行操作?这在 HTTP 协议中是合理的,因为它不打算通过它提供除静态网页之外的任何其他内容。

没有必要很好地适应当前模型 - 即使是纯 HTML。


thx - 如果你想删除整个集合怎么办 - 应该省略 ID 吗?
“我感觉 REST 是……在创建时没有考虑事务之类的小细节”——我不认为这是完全正确的。如果我理解正确,在 REST 中,事务是由资源表示的,而不是由方法表示的。有一些很好的讨论在 this comment on this blog post 中达到高潮。
m
mangelsnc

正如 Decent Dabbler answerrojocas answer 所说,最规范的是使用虚拟资源删除资源选择,但我认为从 REST 角度来看这是不正确的,因为执行 DELETE http://example.com/resources/selections/DF4XY7 应该删除选择资源本身,而不是选定的资源。

Maciej Piechotka anwserfezfox answer 为例,我只有一个反对意见:有一种更规范的方式来传递一个 id 数组,并且使用数组运算符:

DELETE /api/resources?ids[]=1a2b3c4d-5e6f-7a8b-9c0d-1e2f3a4b5c6d&ids[]=7e8f9a0b-1c2d-3e4f-5a6b-7c8d9e0f1a2b

通过这种方式,您正在攻击删除集合端点,但以正确的方式使用查询字符串过滤删除。


u
user103219

由于没有“正确”的方法来做到这一点,我过去所做的是:

在正文中使用 xml 或 json 编码数据将 DELETE 发送到 http://example.com/something

当您收到请求时,检查 DELETE,如果为真,则阅读正文以查找要删除的内容。


这是对我有意义的方法,您只需在一个请求中发送数据,但我总是遇到“但它不是 RESTfull”。您是否有任何消息来源表明这是一种可行且“RESTfull”的方法?
这种方法的问题是 DELETE 操作不需要一个 body,因此 Internet 上的一些中间路由器可能会在您无法控制或不知情的情况下为您删除它。所以使用 body 进行 DELETE 是不安全的!
亚历克斯评论的参考:stackoverflow.com/questions/299628/…
A payload within a DELETE request message has no defined semantics; sending a payload body on a DELETE request might cause some existing implementations to reject the request. 来自 tools.ietf.org/html/rfc7231#section-4.3.5
S
Sherin Syriac

我有同样的情况来删除多个项目。这就是我最终做的。我使用了 DELETE 操作,要删除的项目的 ID 是 HTTP 标头的一部分。