关于rest:实体主体是否允许HTTP DELETE请求?

Is an entity body allowed for an HTTP DELETE request?

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


规范并没有明确地禁止或阻止它,所以我倾向于说它是允许的。

微软也以同样的方式看待它(我能听到听众的低语),他们在msdn的文章中提到了ADO.NET数据服务框架的删除方法:

If a DELETE request includes an entity body, the body is ignored [...]

此外,对于请求,RFC2616(HTTP 1.1)必须说:

  • 实体实体仅在存在消息主体时才存在(第7.2节)
  • 消息体的存在通过包含Content-LengthTransfer-Encoding头(第4.3节)来表示。
  • 当请求方法的规范不允许发送实体实体时,不得包含消息正文(第4.3节)
  • 仅在跟踪请求中明确禁止实体实体,所有其他请求类型都是不受限制的(特别是第9节和第9.8节)

对于响应,定义如下:

  • 是否包含消息体取决于请求方法和响应状态(第4.3节)
  • 在响应头请求时,明确禁止消息体(特别是第9节和第9.4节)
  • 1xx(信息)、204(无内容)和304(未修改)响应中明确禁止消息正文(第4.3节)
  • 所有其他响应都包括消息体,尽管其长度可能为零(第4.3节)


HTTP 1.1规范(RFC7231)的最新更新明确允许删除请求中的实体体:

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.


一些版本的Tomcat和Jetty似乎忽略了实体主体(如果存在的话)。如果你想收到它,这可能会很麻烦。


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

您阅读了记录的版本1。

1
2
GET /some-resource/1
200 OK { id:1, status:"unimportant", version:1 }

您的同事阅读记录的版本1。

1
2
GET /some-resource/1
200 OK { id:1, status:"unimportant", version:1 }

您的同事更改记录并更新数据库,该数据库将版本更新为2:

1
2
PUT /some-resource/1 { id:1, status:"important", version:1 }
200 OK { id:1, status:"important", version:2 }

您尝试删除记录:

1
2
DELETE /some-resource/1 { id:1, version:1 }
409 Conflict

您应该得到一个乐观锁异常。重新阅读记录,看它是否重要,也许不要删除它。

使用它的另一个原因是一次删除多个记录(例如,带有行选择复选框的网格)。

1
2
3
4
DELETE /messages
[{id:1, version:2},
{id:99, version:3}]
204 No Content

请注意,每条消息都有自己的版本。也许您可以使用多个头文件指定多个版本,但是由George来说,这更简单,也更方便。

这适用于Tomcat(7.0.52)和SpringMVC(4.05),可能也适用于早期版本:

1
2
3
4
5
6
7
8
@RestController
public class TestController {

    @RequestMapping(value="/echo-delete", method = RequestMethod.DELETE)
    SomeBean echoDelete(@RequestBody SomeBean someBean) {
        return someBean;
    }
}


在我看来,RFC2616并没有具体说明这一点。

从第4.3节:

The presence of a message-body in a request is signaled by the
inclusion of a Content-Length or Transfer-Encoding header field in
the request's message-headers. A message-body MUST NOT be included in
a request if the specification of the request method (section 5.1.1)
does not allow sending an entity-body in requests. A server SHOULD
read and forward a message-body on any request; if the request method
does not include defined semantics for an entity-body, then the
message-body SHOULD be ignored when handling the request.

以及第9.7节:

The DELETE method requests that the origin server delete the resource
identified by the Request-URI. This method MAY be overridden by human
intervention (or other means) on the origin server. The client cannot
be guaranteed that the operation has been carried out, even if the
status code returned from the origin server indicates that the action
has been completed successfully. However, the server SHOULD NOT
indicate success unless, at the time the response is given, it
intends to delete the resource or move it to an inaccessible
location.

A successful response SHOULD be 200 (OK) if the response includes an
entity describing the status, 202 (Accepted) if the action has not
yet been enacted, or 204 (No Content) if the action has been enacted
but the response does not include an entity.

If the request passes through a cache and the Request-URI identifies
one or more currently cached entities, those entries SHOULD be
treated as stale. Responses to this method are not cacheable.c

因此,这是不允许或不允许的,并且代理可能会删除消息体(尽管它应该读取和转发消息体)。


只是提醒一下,如果您在删除请求中提供了一个主体,并且正在使用GoogleCloudHTTPS负载平衡器,那么它将以400错误拒绝您的请求。我的头撞在墙上,发现谷歌,无论出于什么原因,认为一个带有正文的删除请求是一个畸形的请求。


ElasticSearch似乎使用了以下方法:https://www.elastic.co/guide/en/elastic search/reference/5.x/search-request-scroll.html u clear u-scroll api

这意味着内蒂支持这一点。

就像评论中提到的那样,情况可能不再是这样了。


这是未定义的。

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.
https://tools.ietf.org/html/rfc7231#page-29


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

参考资料见这里和这里

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


如果有人正在进行这个问题测试,不,它不是普遍支持的。

我目前正在使用sahi-pro进行测试,很明显,HTTP删除调用会删除任何提供的主体数据(根据端点设计,大量删除的ID列表)。

我已经和他们联系了好几次,并把三个单独的文件包发给了他们,包括纸条、图片、日志供他们审查,但他们仍然没有证实这一点。一个失败的补丁,一个错过的电话会议,他们的支持,后来,我仍然没有得到一个可靠的答案。

我确信Sahi不支持这一点,并且我可以想象在套件后面还有许多其他的工具。


我不认为有一个很好的答案已经发布,尽管有很多关于现有答案的伟大评论。我将把这些评论的要点提升到一个新的答案中:

这段从RFC7231已经被引用了几次,这是总结。

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请求中包含一个主体,但它在语义上没有意义。这实际上意味着用请求主体发出DELETE请求在语义上等同于不包括请求主体。

包括一个请求主体不应该对请求有任何影响,所以包含它是没有意义的。

tl;dr:从技术上讲,允许使用带有请求主体的DELETE请求,但这样做永远不会有用。


我可以用请求体实现删除操作。我使用了AWS lambda和AWS API网关,并使用了go语言。


将Delete与Body一起使用很危险…对于列表操作,我更喜欢这种方法而不是其他方法:

常规操作

获取/对象/获取所有对象

get/object/id获取具有指定id的对象

发布/对象添加新对象

put/object/id添加具有指定id的对象,更新对象

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

所有自定义操作都已发布

post/objects/addlist添加包含在正文中的对象列表或数组

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

post/objects/custom query基于主体中的自定义查询创建列表

如果客户机不支持您的扩展操作,它们可以正常工作。


可能是下面的github url会帮助你,得到答案。实际上,像Tomcat、Weblogic这样的应用服务器拒绝了带有请求负载的http.delete调用。所以记住这些,我在Github中添加了一个例子,请看一下

https://github.com/ashish720/spring-示例