发出HTTP DELETE请求时,请求URI应完全标识要删除的资源。但是,是否可以在请求的实体中添加额外的元数据?
发出HTTP DELETE请求时,请求URI应完全标识要删除的资源。但是,是否可以在请求的实体中添加额外的元数据?
Answers:
该规范没有明确禁止或阻止它,因此我倾向于说它是允许的。
微软认为它以同样的方式(我可以听到观众低声),他们MSDN文章关于国有ADO.NET数据服务框架的删除方法:
如果DELETE请求包含实体主体,则该主体将被忽略[...]
另外,这是RFC2616(HTTP 1.1)关于请求必须说的内容:
Content-Length
Transfer-Encoding
对于响应,已定义:
HTTP 1.1规范(RFC 7231)的最新更新明确允许DELETE请求中的实体主体:
DELETE请求消息中的有效负载没有定义的语义。在DELETE请求上发送有效内容主体可能会导致某些现有实现拒绝该请求。
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.
因此它带有向后兼容性警告,它暗示下一个标准将是:“是的!DELETE
可以有一个身体。
A payload within a DELETE request message has no defined semantics
。所以身体是允许的。
某些版本的Tomcat和Jetty似乎会忽略实体主体(如果存在)。如果您打算接收,可能会很麻烦。
在删除请求中使用主体的原因之一是为了实现乐观的并发控制。
您阅读记录的版本1。
GET /some-resource/1
200 OK { id:1, status:"unimportant", version:1 }
您的同事读取该记录的版本1。
GET /some-resource/1
200 OK { id:1, status:"unimportant", version:1 }
您的同事更改记录并更新数据库,该数据库将版本更新为2:
PUT /some-resource/1 { id:1, status:"important", version:1 }
200 OK { id:1, status:"important", version:2 }
您尝试删除记录:
DELETE /some-resource/1 { id:1, version:1 }
409 Conflict
您应该获得乐观的锁定异常。重新阅读记录,发现它很重要,也许不删除它。
使用它的另一个原因是一次删除多个记录(例如,带有行选择复选框的网格)。
DELETE /messages
[{id:1, version:2},
{id:99, version:3}]
204 No Content
请注意,每个消息都有其自己的版本。也许您可以使用多个标头指定多个版本,但是对于George来说,这更简单,更方便。
这适用于Tomcat(7.0.52)和Spring MVC(4.05),可能也适用于早期版本:
@RestController
public class TestController {
@RequestMapping(value="/echo-delete", method = RequestMethod.DELETE)
SomeBean echoDelete(@RequestBody SomeBean someBean) {
return someBean;
}
}
If-Unmodified-Since
或Etag
,这就是它们的用途)。
在我看来,RFC 2616没有指定这一点。
从第4.3节开始:
通过在请求的消息头中包含Content-Length或Transfer-Encoding头字段,可以指示请求中消息主体的存在。如果请求方法的规范(第5.1.1节)不允许在请求中发送实体,则消息体不得包含在请求中。服务器应根据任何请求读取并转发消息正文;如果请求方法不包含为实体主体定义的语义,则在处理请求时应忽略消息主体。
以及第9.7节:
DELETE方法请求原始服务器删除由Request-URI标识的资源。在原始服务器上,人为干预(或其他方式)可能会覆盖此方法。即使从原始服务器返回的状态代码指示该操作已成功完成,也不能保证客户机已经执行了该操作。但是,服务器不应指示成功,除非在给出响应时服务器打算删除资源或将其移动到无法访问的位置。
如果响应包含描述状态的实体,则成功响应应为200(确定);如果尚未执行该操作,则为202(接受);如果已执行该动作但响应不包括该响应,则返回204(无内容)。一个实体。
如果请求通过缓存,并且Request-URI标识一个或多个当前缓存的实体,则应将这些条目视为过期。对此方法的响应不可缓存。
因此,它没有被明确允许或禁止,并且沿途的代理可能会删除消息正文(尽管它应该读取并转发它)。
请注意,如果您在DELETE请求中提供了正文,并且正在使用Google Cloud HTTPS负载均衡器,它将拒绝您的请求,并显示400错误。我撞墙碰壁,结果发现Google出于某种原因认为带有主体的DELETE请求是格式错误的请求。
for whatever reason
-因为规范是这样说的:P
DELETE
后者使用消息正文。
似乎ElasticSearch使用以下代码:https ://www.elastic.co/guide/zh-CN/elasticsearch/reference/5.x/search-request-scroll.html#_clear_scroll_api
这意味着Netty支持这一点。
就像评论中提到的那样,情况可能不再如此
HTTP邮件列表上的Roy Fielding澄清了HTTP邮件列表 https://lists.w3.org/Archives/Public/ietf-http-wg/2020JanMar/0123.html上的内容,并说:
绝对禁止GET / DELETE正文对请求的处理或解释产生任何影响
这意味着主体不得修改服务器的行为。然后他补充说:
除了必须读取和丢弃接收到的字节以维持消息帧外,还需要其他方法。
最后,禁止身体的原因:
我们不禁止发送正文的唯一原因是,如果不发送正文,这将导致延迟实现。
因此,尽管客户端可以发送有效内容主体,但服务器应丢弃它,并且API不应在这些请求上为有效内容主体定义语义。
没有定义。
DELETE请求消息中的有效负载没有定义的语义。在DELETE请求上发送有效内容主体可能会导致某些现有实现拒绝该请求。
https://tools.ietf.org/html/rfc7231#page-29
与主体一起使用DELETE是有风险的...与REST相比,我更喜欢这种用于列表操作的方法:
常规运营
GET / objects / 获取所有对象
GET / object / ID 获取具有指定ID的对象
POST / objects 添加一个新的对象
PUT / object / ID 添加具有指定ID的对象,更新对象
DELETE / object / ID 删除具有指定ID的对象
所有自定义操作均为POST
POST / objects / addList 添加主体中包含的对象的列表或数组
POST / objects / deleteList 删除主体中包含的对象列表
POST / objects / customQuery 基于正文中的自定义查询创建一个列表
如果客户不支持您的扩展操作,他们可以按常规方式工作。
POST
REST并不是创建新资源的良好RESTy方法,因为POST响应的语义尚不清楚,尤其是在Location标头的上下文中。您实际上是将HTTP留在了后面,而将RPC堆叠在了上面。正确的“ HTTP / REST方式”是使用PUT
带有If-None-Match: *
标头的资源(或指定正确的HTTP方法,请参见MKCOL
等)来创建资源。
我不认为已经发布了一个好的答案,尽管对现有答案有很多不错的评论。我将这些评论的要点变成一个新的答案:
RFC7231的这一段已经被引用了几次,并对其进行了总结。
DELETE请求消息中的有效负载没有定义的语义。在DELETE请求上发送有效内容主体可能会导致某些现有实现拒绝该请求。
我从其他答案中错过的是含义。是的,可以在DELETE
请求中包含主体,但是在语义上是没有意义的。这的真正含义是,发出DELETE
带有请求正文的请求在语义上等同于不包括请求正文。
包含请求正文对请求不会有任何影响,因此将其包含在内永远没有意义。
tl; dr:从技术上讲DELETE
,允许带有请求正文的请求,但这样做从来没有用。
如果有人正在测试此问题,则不普遍不支持它。
我目前正在使用Sahi Pro进行测试,很明显,http DELETE调用会剥离任何提供的主体数据(根据端点设计,要删除的大量ID列表)。
我已经与他们联系了好几次,并以三个单独的纸条,图像,日志包发送给他们进行审核,但他们仍然没有确认。补丁程序失败,后来错过了他们的支持所召开的电话会议,但我仍然没有得到可靠的答案。
我确定Sahi不支持此功能,并且我可以想象还有许多其他工具会随套件提供。
可能是下面的GitHUb网址会帮助您,获得答案。实际上,像Tomcat这样的Application Server,Weblogic拒绝带有请求有效负载的HTTP.DELETE调用。因此请牢记所有这些内容,我在github中添加了示例,请查看一下