114

虽然HTTP 1.1 规范似乎允许DELETE请求上的消息体,但它似乎表明服务器应该忽略它,因为它没有定义的语义。

4.3 消息体

服务器应该在任何请求上读取并转发消息体;如果请求方法不包括为实体主体定义的语义,则在处理请求时应该忽略消息主体。

我已经回顾了关于 SO 及其他主题的几个相关讨论,例如:

大多数讨论似乎都同意在 DELETE 上提供消息正文可能是允许的,但通常不建议这样做。

此外,我注意到各种 HTTP 客户端库中的一种趋势,这些库似乎正在记录越来越多的增强功能,以支持 DELETE 上的请求正文。大多数图书馆似乎都有义务,尽管偶尔会有一点最初的阻力。

我的用例要求在 DELETE 上添加一些必需的元数据(例如,删除的“原因”,以及删除所需的一些其他元数据)。我考虑了以下选项,但这些选项似乎都不完全合适且符合 HTTP 规范和/或 REST 最佳实践:

  • 消息体- 规范表明 DELETE 上的消息体没有语义值;HTTP 客户端不完全支持;非标准做法
  • 自定义 HTTP 标头- 要求自定义标头通常违反标准做法;使用它们与我的 API 的其余部分不一致,这些都不需要自定义标头;此外,没有好的 HTTP 响应可用于指示错误的自定义标头值(可能完全是一个单独的问题)
  • 标准 HTTP 标头- 没有合适的标准标头
  • 查询参数- 添加查询参数实际上会更改被删除的请求 URI;违反标准做法
  • POST 方法-(例如POST /resourceToDelete { deletemetadata })POST 不是删除的语义选项;POST 实际上代表期望的相反动作(即 POST 创建资源下属;但我需要删除资源)
  • 多种方法- 将 DELETE 请求拆分为两个操作(例如 PUT 删除元数据,然后删除)将原子操作拆分为两个,可能会留下不一致的状态。删除原因(和其他相关元数据)不是资源表示本身的一部分。

我的第一个偏好可能是使用消息正文,其次是自定义 HTTP 标头;然而,如前所述,这些方法也有一些缺点。

是否有任何符合 REST/HTTP 标准的建议或最佳实践来在 DELETE 请求中包含此类必需的元数据?还有其他我没有考虑过的替代方案吗?

4

4 回答 4

52

尽管有一些建议不要将消息正文用于 DELETE 请求,但这种方法在某些用例中可能是合适的。这是我们在评估问题/答案中提到的其他选项并与服务的消费者合作之后最终使用的方法。

虽然消息正文的使用并不理想,但其他选项都不是完全合适的。请求正文 DELETE 使我们能够轻松清晰地围绕 DELETE 操作所需的附加数据/元数据添加语义。

我仍然愿意接受其他想法和讨论,但想结束这个问题的循环。感谢大家对这个话题的想法和讨论!

于 2013-03-18T16:36:19.890 回答
12

您似乎想要的是两件事之一,两者都不是纯粹的DELETE

  1. 您有两个操作,一个PUT是删除原因,一个DELETE是资源。删除后,任何人都无法再访问该资源的内容。“原因”不能包含指向已删除资源的超链接。或者,
  2. 您正在尝试使用该方法将资源从state=active更改为 。state=deleted 的资源会被您的主 API 忽略,但管理员或具有数据库访问权限的人可能仍然可以读取。这是允许的 -不必删除资源的支持数据,只需删除在该 URI 处公开的资源。state=deletedDELETEDELETE

任何需要消息体的操作DELETE都可以被分解为最一般的,aPOST用消息体完成所有必要的任务,和DELETE. 我认为没有理由破坏 HTTP 的语义。

于 2013-01-15T09:10:13.347 回答
10

Given the situation you have, I would take one of the following approaches:

  • Send a PUT or PATCH: I am deducing that the delete operation is virtual, by the nature of needing a delete reason. Therefore, I believe updating the record via a PUT/PATCH operation is a valid approach, even though it is not a DELETE operation per se.
  • Use the query parameters: The resource uri is not being changed. I actually think this is also a valid approach. The question you linked was talking about not allowing the delete if the query parameter was missing. In your case, I would just have a default reason if the reason is not specified in the query string. The resource will still be resource/:id. You can make it discoverable with Link headers on the resource for each reason (with a rel tag on each to identify the reason).
  • Use a separate endpoint per reason: Using a url like resource/:id/canceled. This does actually change the Request-URI and is definitely not RESTful. Again, link headers can make this discoverable.

Remember that REST is not law or dogma. Think of it more as guidance. So, when it makes sense to not follow the guidance for your problem domain, don't. Just make sure your API consumers are informed of the variance.

于 2013-01-15T05:37:24.603 回答
0

我建议您将所需的元数据作为 URI 层次结构本身的一部分。一个例子(天真):

如果您需要根据日期范围删除条目,而不是在正文中或作为查询参数传递开始日期和结束日期,请构建 URI,以便将所需信息作为 URI 的一部分传递。

例如

DELETE /entries/range/01012012/31122012-- 删除 2012 年 1 月 1 日至 2012 年 12 月 31 日之间的所有条目

希望这可以帮助。

于 2013-01-15T07:07:51.987 回答