实体主体是否允许HTTP DELETE请求?

时间:2008-11-18 18:14:27

标签: http rest

发出HTTP DELETE请求时,请求URI应完全标识要删除的资源。但是,是否允许添加额外的元数据作为请求的实体主体的一部分?

16 个答案:

答案 0 :(得分:490)

The spec没有明确禁止或劝阻它,所以我倾向于说它是允许的。

微软以同样的方式看待它(我可以听到观众中的嘀咕声),他们在MSDN文章中指出DELETE Method of ADO.NET Data Services Framework

  

如果DELETE请求包含实体主体,则会忽略正文[...]

此外,RFC2616(HTTP 1.1)对请求的说法如下:

  • entity-body 仅在存在 message-body 时出现(第7.2节)
  • 通过包含Content-LengthTransfer-Encoding标题(第4.3节)来表示存在消息正文
  • 当请求方法的规范不允许发送 entity-body 时,不得包含 message-body (第4.3节)
  • 仅在TRACE请求中明确禁止 entity-body ,所有其他请求类型不受限制(第9节和第9.节)

对于回复,已定义:

  • 是否包含 message-body 取决于请求方法响应状态(第4.3节)
  • 在对HEAD请求的响应中明确禁止 message-body (具体为第9节和第9.4节)
  • 在1xx(信息),204(无内容)和304(未修改)响应中明确禁止 message-body (第4.3节)
  • 所有其他回复都包含一个消息体,尽管它可能是零长度(第4.3节)

答案 1 :(得分:144)

HTTP 1.1规范的最新更新(RFC 7231)明确允许DELETE请求中的实体主体:

  

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

答案 2 :(得分:52)

某些版本的Tomcat和Jetty似乎忽略了实体主体(如果存在)。如果您打算收到它,这可能会令人讨厌。

答案 3 :(得分:44)

在删除请求中使用正文的一个原因是乐观并发控制。

您阅读的是记录的第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;
    }
}

答案 4 :(得分:27)

在我看来,RFC 2616没有指明这一点。

从第4.3节开始:

  

请求中存在消息正文   包含Content-Length或Transfer-Encoding标头字段   请求的消息头。邮件正文不得包含在内   如果请求方法的规范请求(第5.1.1节)   不允许在请求中发送实体主体。服务器应该   在任何请求上读取和转发消息正文;如果是请求方法   不包含实体主体的定义语义,然后是   处理请求时,应该忽略message-body。

第9.7节:

  

DELETE方法请求源服务器删除资源   由Request-URI标识。这种方法可以被人类覆盖   原始服务器上的干预(或其他方式)。客户不能   保证操作已经进行,即使是   从原始服务器返回的状态代码表示该操作   已成功完成。但是,服务器不应该   除非在给出答复时表明成功   打算删除资源或将其移动到无法访问的资源   位置。

     

如果响应包含一个,那么成功的响应应该是200(OK)   描述状态的实体,202(已接受),如果操作没有   尚未颁布,或204(无内容),如果该行动已经颁布   但是回复不包括实体。

     

如果请求通过缓存并且Request-URI标识   一个或多个当前缓存的实体,这些条目应该是   被视为陈旧。对此方法的响应不是cacheable.c

所以它没有被明确允许或禁止,并且沿途的代理可能会删除消息体(尽管它应该读取并转发它)。

答案 5 :(得分:15)

如果您在DELETE请求中提供正文并且正在使用Google云端HTTPS负载均衡器,那么它将拒绝您的请求,并出现400错误。我正撞在墙上,发现Google无论出于何种原因认为带有正文的DELETE请求是一个格式错误的请求。

答案 6 :(得分:12)

HTTP邮件列表上的Roy Fielding澄清了http邮件列表https://lists.w3.org/Archives/Public/ietf-http-wg/2020JanMar/0123.html上的内容,并说:

GET / DELETE身体绝对禁止有任何影响 处理或解释请求

这意味着主体不得修改服务器的行为。 然后他添加:

除了 读取和丢弃接收到的字节以保持其必要性 消息框架。

最后是禁止遗体的原因:

我们不禁止发送尸体的唯一原因是 因为假设没有人会导致懒惰的实现 被发送。

因此,尽管客户端可以发送有效内容主体,但服务器应将其丢弃 并且API不应在这些请求上为有效载荷主体定义语义。

答案 7 :(得分:7)

ElasticSearch似乎使用了这个: https://www.elastic.co/guide/en/elasticsearch/reference/5.x/search-request-scroll.html#_clear_scroll_api

这意味着Netty支持这一点。

在评论中提到它可能不再是这种情况

答案 8 :(得分:6)

未定义

  

DELETE请求消息中的有效负载没有定义的语义;      在DELETE请求上发送有效负载主体可能会导致某些存在      拒绝请求的实现。
  https://tools.ietf.org/html/rfc7231#page-29

答案 9 :(得分:5)

值得注意的是,版本3.0的OpenAPI规范删除了对带有主体的DELETE方法的支持:

请参见herehere以获取参考

这将来可能会影响您的实现,文档或这些API的使用。

答案 10 :(得分:3)

如果有人遇到此问题测试,请不要普遍支持。

我目前正在使用Sahi Pro进行测试,很明显一个http DELETE调用剥离任何提供的正文数据(根据端点设计批量删除大量的id)。

我已经多次与他们联系,并且发送了三个单独的包裹,图像,日志包供他们审查,他们仍然没有证实这一点。一个失败的补丁,以及之后他们的支持错过了电话会议,我仍然没有得到一个可靠的答案。

我确信Sahi不支持这一点,我会想到许多其他工具都可以使用套件。

答案 11 :(得分:3)

尽管现有答案有很多不错的评论,但我认为对此并没有给出很好的答案。我将这些评论的要点变成一个新的答案:

This paragraph from RFC7231被引用了几次,但确实将其汇总。

  

DELETE请求消息中的有效负载没有定义的语义;      在DELETE请求上发送有效内容正文可能会导致一些现有内容      拒绝请求的实现。

我从其他答案中错过的是含义。是的,它可以在DELETE请求中包含正文,但是在语义上是没有意义的。这的真正含义是,发出带有请求正文的DELETE请求在语义上等同于不包括请求正文。

包括请求正文对请求不会有任何影响,因此将其包含在内根本没有意义。

tl; dr:从技术上讲,允许带有请求正文的DELETE请求,但这样做绝对没有用。

答案 12 :(得分:1)

我能够通过Request主体实现DELETE操作。我使用了AWS Lambda和AWS API网关,并使用了Go语言。

答案 13 :(得分:0)

与主体一起使用DELETE是有风险的...与REST相比,我更喜欢这种用于列表操作的方法:

常规操作

获取 / objects / 获取所有对象

获取 / object / ID 获取具有指定ID的对象

POST /对象 添加新对象

输入 / object / ID 添加具有指定ID的对象,更新对象

删除 / object / ID 删除具有指定ID的对象

所有自定义操作均为POST

POST / objects / addList 添加正文中包含的对象列表或对象

POST / objects / deleteList 删除正文中包含的对象列表

POST / objects / customQuery 基于正文中的自定义查询创建列表

如果客户不支持您的扩展操作,他们可以按常规方式工作。

答案 14 :(得分:0)

实际答案:否

一些客户端和服务器会忽略甚至删除 DELETE 请求中的正文。在极少数情况下,它们会失败并返回错误。

答案 15 :(得分:-1)

下面的GitHUb网址可能会帮助您获得答案。 实际上,像Tomcat这样的Application Server,Weblogic拒绝带有请求有效负载的HTTP.DELETE调用。因此请牢记所有这些内容,我在github中添加了示例,请仔细阅读

https://github.com/ashish720/spring-examples