DELETE Request Body的RESTful替代方案

she*_*ley 86 rest http httprequest http-method

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

4.3消息正文

服务器应该在任何请求上读取和转发消息体; 如果请求方法不包含实体主体的定义语义,那么在处理请求时应该忽略消息主体.

我已经回顾了有关SO及其他内容的几个相关讨论,例如:

大多数讨论似乎都同意允许在DELETE上提供消息体,但通常不建议这样做.

此外,我注意到各种HTTP客户端库中的趋势,这些库中似乎记录了越来越多的增强功能,以支持DELETE上的请求主体.大多数图书馆似乎都有责任,尽管偶尔会有一些初步阻力.

我的用例要求在DELETE上添加一些必需的元数据(例如删除的"原因",以及删除所需的一些其他元数据).我已经考虑了以下选项,其中任何一个看起来都不合适,并且与HTTP规范和/或REST最佳实践内联:

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

我的第一个偏好可能是使用消息体,第二个是自定义HTTP头; 但是,如上所述,这些方法存在一些缺点.

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

she*_*ley 41

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

虽然消息体的使用并不理想,但其他选项都不是完全适合的.请求体DELETE允许我们轻松,清晰地添加伴随DELETE操作所需的其他数据/元数据的语义.

我仍然对其他想法和讨论持开放态度,但想要关闭这个问题的循环.我感谢大家对这个主题的想法和讨论!

  • 这是一个坏主意.如果您以后决定使用像Akamai EdgeConnect这样的HTTP加速服务,那么这会让您遇到麻烦.我知道EdgeConnect从HTTP DELETE请求中剥离主体(因为它们消耗带宽可能无效).类似的服务也可能做同样的事情(参见Kindle的加速功能和其他类似CDN的服务).您可能应该重新设计为不为您的服务使用HTTP谓词.大多数API使用HTTP-verbs/classical-REST没有多大意义,HTTP动词传输问题很难排除故障. (11认同)
  • 这些反对使用 DELETE 的评论是无关紧要的,直到它们解决了 OP 所存在的非常有效的问题。我尽力遵循 REST 精神,但没有乐观并发的删除和没有原子批处理操作的删除在现实情况下是不切实际的。这是 REST 模式的严重缺陷。 (5认同)
  • 我同意@Gabe,根据定义发送一个没有主体**的方法**是一种可靠的方法,当你的位遍历互联网管道时随机丢失数据,你将很难调试它. (3认同)
  • 我同意@Quarkly 的观点。我不明白关于如何检查并发性等的 RESTFUL 想法是什么。并发性检查不属于客户端。 (2认同)

Nic*_*nks 13

你似乎想要的是两件事之一,它们都不是纯粹的DELETE:

  1. 您有两个操作,一个PUT是删除原因,后跟一个DELETE资源.删除后,任何人都无法再访问该资源的内容."原因"不能包含指向已删除资源的超链接.要么,
  2. 您正在试图改变资源state=activestate=deleted使用DELETE方法.主API会忽略state = deleted的资源,但对于管理员或具有数据库访问权限的人员可能仍然可以读取.这是允许的 - DELETE不必擦除资源的后备数据,只删除在该URI上公开的资源.

任何需要DELETE请求消息体的操作都可以分解为最常见的操作,a POST用消息体执行所有必要的任务,以及a DELETE.我认为没有理由打破HTTP的语义.

  • 如果`PUT`原因成功并且'DELETE`资源失败会发生什么?如何防止不一致的状态? (2认同)

cod*_*ion 7

鉴于你的情况,我会采取以下方法之一:

  • 发送PUT或PATCH:由于需要删除原因,我推断删除操作是虚拟的.因此,我认为通过PUT/PATCH操作更新记录是一种有效的方法,即使它本身不是DELETE操作.
  • 使用查询参数:资源uri未更改.我实际上认为这也是一种有效的方法.您链接的问题是在缺少查询参数时讨论不允许删除.在您的情况下,如果未在查询字符串中指定原因,我将只有默认原因.资源仍然是resource/:id.您可以使用资源上的链接标头为每个原因使其可被发现(每个原因rel上都有一个标记来标识原因).
  • 每个原因使用一个单独的端点:使用类似的URL resource/:id/canceled.这确实改变了Request-URI,绝对不是RESTful.同样,链接标题可以使这个可被发现.

请记住,REST不是法律或教条.将其视为指导.因此,如果不遵循问题域的指导是有意义的,请不要这样做.只需确保您的API使用者了解差异.