Um corpo de entidade é permitido para uma solicitação HTTP DELETE?


717

Ao emitir uma solicitação HTTP DELETE, o URI da solicitação deve identificar completamente o recurso a ser excluído. No entanto, é permitido adicionar metadados extras como parte do corpo da entidade da solicitação?


4
No ASP.NET WebApi 2 FromBody, os parâmetros são ignorados para os pontos de extremidade HttpDelete.
Jenny O'Reilly

2
Eu tenho uma preocupação semelhante, mas meu caso é diferente. Quero emitir uma solicitação de exclusão em lote quando desejar excluir cem objetos. Certamente, é um grande aumento de desempenho para redes pré-HTTP 2.0.
Singagirl 19/09/16

1
Houve alguma alteração no HTTP / 2?
Jyotman Singh

Respostas:


570

A especificação não a proíbe ou desencoraja explicitamente, então eu diria que é permitido.

A Microsoft vê da mesma maneira (posso ouvir murmúrios na platéia), afirmam no artigo do MSDN sobre o método DELETE do ADO.NET Data Services Framework :

Se uma solicitação DELETE incluir um corpo da entidade, o corpo será ignorado [...]

Além disso, aqui está o que o RFC2616 (HTTP 1.1) tem a dizer em relação aos pedidos:

  • um corpo da entidade está presente apenas quando um corpo da mensagem está presente (seção 7.2)
  • a presença de um corpo da mensagem é sinalizada pela inclusão de um cabeçalho Content-Lengthou Transfer-Encoding(seção 4.3)
  • um corpo da mensagem não deve ser incluído quando a especificação do método de solicitação não permitir o envio de um corpo da entidade (seção 4.3)
  • um corpo da entidade é explicitamente proibido apenas em solicitações TRACE, todos os outros tipos de solicitação são irrestritos (seção 9 e 9.8 especificamente)

Para respostas, isso foi definido:

  • se um corpo da mensagem está incluído depende do método de solicitação e do status da resposta (seção 4.3)
  • um corpo da mensagem é explicitamente proibido nas respostas às solicitações HEAD (seção 9 e 9.4 especificamente)
  • um corpo da mensagem é explicitamente proibido nas respostas 1xx (informativas), 204 (sem conteúdo) e 304 (não modificadas) (seção 4.3)
  • todas as outras respostas incluem um corpo da mensagem, embora possa ter comprimento zero (seção 4.3)

7
@Jason Definitivamente. Você também pode usar cabeçalhos personalizados para passar dados adicionais, mas por que não usar o corpo da solicitação.
precisa

86
Embora a especificação não proíba pedidos DELETE de ter um corpo da mensagem, a seção 4.3 parece indicar que o corpo deve ser ignorado pelos servidores, pois não há "semântica definida" para os corpos de entidade DELETE : "Um servidor DEVE ler e encaminhar um corpo da mensagem em qualquer solicitação; se o método de solicitação não incluir semântica definida para um corpo da entidade, o corpo da mensagem DEVE ser ignorado ao manipular a solicitação . "
Shelley

72
Observe que muitos clientes também não conseguem enviar um DELETE com um corpo. Isso me queimou no Android.
Karmic Coder

1
@KarmicCoder: Ótimo ponto. Mais informações: Enviando solicitação HTTP DELETE no Android .
MS Dousti 25/10/2015

2
Muita discussão sobre implementação combinada com especificações HTTP. Os clientes irão implementar as coisas da maneira que interpretam as especificações, não confunda isso com o significado das especificações. O fato é que as especificações deixam isso ambíguo. Discordo da interpretação de que, como não há semântica definida para o corpo da entidade, existe uma implicação de que ele deva ser ignorado. Eu acho que as pessoas estão trabalhando de trás para frente a partir de interpretações específicas de clientes existentes (Jersey, clientes de teste do Android etc.) e tentando justificar a interpretação, em vez de tentar se manter fiel às especificações. Os seres humanos são falíveis.
precisa saber é o seguinte

169

A atualização mais recente da especificação HTTP 1.1 ( RFC 7231 ) permite explicitamente um corpo de entidade em uma solicitação DELETE:

Uma carga útil em uma mensagem de solicitação DELETE não possui semântica definida; enviar um corpo de carga útil em uma solicitação DELETE pode fazer com que algumas implementações existentes rejeitem a solicitação.


3
a versão não aprovada mais recente da especificação remove esse requisito. A versão mais recente aprovada ainda é a RFC2616 citada acima.
BishopZ

4
Qual versão? A versão 20 ainda possui a mesma redação da versão 19 que eu vinculei acima: "Os corpos em solicitações DELETE não possuem semântica definida. Observe que o envio de um corpo em uma solicitação DELETE pode fazer com que algumas implementações existentes rejeitem a solicitação."
grzes

11
A versão 26 sugere que você pode permitir um corpo: 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.Portanto, ele vem com um aviso de compatibilidade com versões anteriores, sugerindo que o próximo padrão esteja dizendo: 'sim! DELETEpode ter um corpo.
Pure.Krome

4
A seção 4.3.5 da RFC 7231 finaliza o idioma da versão 26 com A payload within a DELETE request message has no defined semantics. Então o corpo é permitido.
mndrix

6
O corpo é permitido, mas não deve ser relevante para a solicitação. Não há absolutamente nenhum sentido em usá-lo.
Evert


50

Um motivo para usar o corpo em uma solicitação de exclusão é o controle de concorrência otimista.

Você lê a versão 1 de um registro.

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

Seu colega lê a versão 1 do registro.

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

Seu colega altera o registro e atualiza o banco de dados, que atualiza a versão para 2:

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

Você tenta excluir o registro:

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

Você deve obter uma exceção de bloqueio otimista. Releia o registro, veja se é importante e talvez não o exclua.

Outro motivo para usá-lo é excluir vários registros por vez (por exemplo, uma grade com caixas de seleção de seleção de linha).

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

Observe que cada mensagem tem sua própria versão. Talvez você possa especificar várias versões usando vários cabeçalhos, mas, por George, isso é mais simples e muito mais conveniente.

Isso funciona no Tomcat (7.0.52) e no Spring MVC (4.05), possivelmente também nas versões anteriores:

@RestController
public class TestController {

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

15
Ter corpos em GET (e DELETE) está claramente maltratando HTTP e REST. Existem outros mecanismos para lidar com o controle de concorrência (por exemplo, If-Modified-Since e etags).
187 Bruno

19
Como é maltratá-lo claramente quando a especificação não proíbe o corpo em DELETE?
Neil McGuigan

5
Porque você não deve fazer nada com o corpo. Veja: stackoverflow.com/a/983458/372643
Bruno

14
Esse é exatamente o mesmo problema: GET permite recuperar a representação do recurso identificado pelo URI e DELETE exclui o recurso identificado pelo URI. Use um URI diferente para outras versões se desejar excluir versões específicas. O URI deve ser o único identificador do recurso em HTTP / REST. Use metadados nos cabeçalhos se precisar lidar com a simultaneidade (por exemplo , If-Unmodified-Sinceou Etagé para isso que servem).
de Bruno

5
Use ETag cabeçalho em vez de um campo de versão em um corpo
malhal

26

Parece-me que o RFC 2616 não especifica isso.

Na seção 4.3:

A presença de um corpo da mensagem em uma solicitação é sinalizada pela inclusão de um campo de cabeçalho Content-Length ou Transfer-Encoding nos cabeçalhos da mensagem da solicitação. Um corpo da mensagem NÃO DEVE ser incluído em uma solicitação se a especificação do método da solicitação (seção 5.1.1) não permitir o envio de uma entidade na solicitação. Um servidor deve ler e encaminhar um corpo da mensagem em qualquer solicitação; se o método de solicitação não inclui semântica definida para um corpo de entidade, o corpo da mensagem DEVE ser ignorado ao manipular o pedido.

E seção 9.7:

O método DELETE solicita que o servidor de origem exclua o recurso identificado pelo Request-URI. Este método pode ser substituído por intervenção humana (ou outros meios) no servidor de origem. Não é possível garantir ao cliente que a operação foi realizada, mesmo que o código de status retornado do servidor de origem indique que a ação foi concluída com êxito. No entanto, o servidor NÃO DEVE indicar sucesso, a menos que, no momento em que a resposta seja dada, pretenda excluir o recurso ou movê-lo para um local inacessível.

Uma resposta bem-sucedida DEVE ser 200 (OK) se a resposta incluir uma entidade que descreve o status, 202 (Aceito) se a ação ainda não foi promulgada ou 204 (Sem Conteúdo) se a ação foi promulgada, mas a resposta não incluir uma entidade.

Se o pedido passa através de um cache e o Request-URI identifica uma ou mais entidades atualmente em cache, essas entradas devem ser tratadas como obsoletas. As respostas a este método não são armazenáveis ​​em cache.c

Portanto, não é explicitamente permitido ou proibido, e há uma chance de que um proxy ao longo do caminho remova o corpo da mensagem (embora DEVE ler e encaminhar).


19

Se você fornecer um corpo em sua solicitação DELETE e estiver usando um balanceador de carga HTTPS do Google Cloud, ele rejeitará sua solicitação com um erro 400. Eu estava batendo minha cabeça contra uma parede e descobri que o Google, por qualquer motivo, acha que uma solicitação DELETE com um corpo é uma solicitação incorreta.


1
for whatever reason- porque a especificação diz o seguinte: P
Mardoxx 27/02

20
A especificação não "diz isso", apenas diz que o corpo não está definido especificamente. Se não estiver definido, e você quiser ignorá-lo, legal ... vá em frente e ignore. Mas rejeitar o pedido imediatamente parece extremo e desnecessário.
Ben Fried

1
Não confie em comportamento indefinido. É uma prática recomendada bastante comum.
Evert

@Evert existe um comportamento explicitamente indefinido (como você descreve nas especificações da linguagem C, por exemplo) e há um comportamento permitido, mas simplesmente não descrito. Usar um corpo da mensagem DELETEé o último.
Alnitak

9

Vale ressaltar que a especificação OpenAPI da versão 3.0 descartou o suporte aos métodos DELETE com um corpo:

veja aqui e aqui para referências

Isso pode afetar sua implementação, documentação ou uso dessas APIs no futuro.


7

Parece que o ElasticSearch usa: https://www.elastic.co/guide/en/elasticsearch/reference/5.x/search-request-scroll.html#_clear_scroll_api

O que significa que o Netty suporta isso.

Como mencionado nos comentários, pode não ser mais o caso


1
Se você usar o cliente http apache, poderá criar facilmente suas próprias versões de GET e DELETE estendendo HttpEntityEnclosingRequestBase e fazendo com que o método getMethod () retorne GET ou DELETE. Usamos isso para conversar com elasticsearch.
Jilles van Gurp

2
link morto - ótimo. precisamos mais desses links respostas - não
cottton

3
A documentação vinculada agora contém apenas solicitações POST, sem DELETEs. Pode valer a pena adicionar uma nota a esta resposta?
dshepherd

O Elasticsearch também usa body com solicitações GET.
Nidhin David

7

Roy Fielding, na lista de correspondência HTTP, esclarece que na lista de correspondência http https://lists.w3.org/Archives/Public/ietf-http-wg/2020JanMar/0123.html e diz:

É absolutamente proibido ao organismo GET / DELETE ter qualquer impacto no processamento ou interpretação da solicitação

Isso significa que o corpo não deve modificar o comportamento do servidor. Então ele acrescenta:

além da necessidade de ler e descartar os bytes recebidos para manter o enquadramento da mensagem.

E, finalmente, o motivo de não proibir o corpo:

A única razão pela qual não proibimos o envio de um corpo é porque isso levaria a implementações preguiçosas, assumindo que nenhum corpo seria enviado.

Portanto, embora os clientes possam enviar o corpo da carga útil, os servidores devem descartá-lo e as APIs não devem definir uma semântica para o corpo da carga útil nessas solicitações.



5

Usar DELETE com um corpo é arriscado ... Prefiro essa abordagem para operações de lista em vez de REST:

Operações regulares

GET / objects / Obtém todos os objetos

GET / object / ID Obtém um objeto com o ID especificado

POST / objetos Adiciona um novo objeto

PUT / objeto / ID Adiciona um objeto com o ID especificado, atualiza um objeto

DELETE / object / ID Exclui o objeto com o ID especificado

Todas as ações personalizadas são POST

POST / objects / addList Adiciona uma lista ou matriz de objetos incluídos no corpo

POST / objects / deleteList Exclui uma lista de objetos incluídos no corpo

POST / objects / customQuery Cria uma lista com base na consulta personalizada no corpo

Se um cliente não suportar suas operações estendidas, ele poderá trabalhar de maneira regular.


Usar a POSTnão é uma boa maneira RESTy de criar novos recursos, porque a semântica das respostas POST não é clara, especialmente no contexto dos cabeçalhos de Localização. Você está essencialmente deixando o HTTP para trás e empilhando o RPC no topo. A "maneira HTTP / REST" apropriada é criar recursos usando PUTo If-None-Match: *cabeçalho (ou especificando métodos HTTP apropriados, consulte MKCOLetc).
hnh 22/03/19

4

Eu não acho que uma boa resposta para isso tenha sido publicada, embora tenha havido muitos ótimos comentários sobre as respostas existentes. Vou levantar a essência desses comentários para uma nova resposta:

Este parágrafo do RFC7231 foi citado algumas vezes, o que resume .

Uma carga útil em uma mensagem de solicitação DELETE não possui semântica definida; enviar um corpo de carga em uma solicitação DELETE pode fazer com que algumas implementações existentes rejeitem a solicitação.

O que eu perdi das outras respostas foi a implicação. Sim, é permitido incluir um corpo nos DELETEpedidos, mas é semanticamente sem sentido. O que isso realmente significa é que emitir uma DELETEsolicitação com um corpo de solicitação é semanticamente equivalente a não incluir um corpo de solicitação.

A inclusão de um corpo da solicitação não deve ter nenhum efeito sobre a solicitação, portanto nunca há sentido em incluí-la.

tl; dr: Tecnicamente, uma DELETEsolicitação com um corpo de solicitação é permitida, mas nunca é útil fazer isso.


2
"semanticamente sem sentido" não significa o mesmo que "não possui semântica definida". O primeiro significa que não pode ter nenhum significado. O último significa simplesmente que o próprio RFC não especifica o que essas semânticas podem ser. (Escrevo RFCs)
Alnitak

1
Em outras palavras, se o implementador de uma API deseja definir alguma semântica para si, é perfeitamente livre para fazê-lo.
Alnitak

1
@ Alnitak, esta é definitivamente uma má interpretação. Por essa definição, qualquer corpo de solicitação HTTP não possui semântica definida, mas DELETE e GET são especificamente chamados na especificação. Aqui está um trecho de um rascunho ainda a ser publicado, falando sobre isso especificamente sobre a solicitação GET: #:
Evert

1
Não discordo de você que isso não esteja claro nas RFCs atualmente lançadas, mas se você não acredita em mim, convidaria você a perguntar aos autores sobre a intenção deles de DELETE e GET. Você verá que está alinhado com a minha resposta. Como você, eu também estou envolvido em órgãos de normas e não sou apenas uma pessoa solitária com uma opinião sobre como a RFC deve ser interpretada.
Evert

2
Se for esse o caso, o 7231 é mal formulado e deveria ter dito "o corpo da carga DEVE ser ignorado". A que rascunho você está se referindo acima?
Alnitak

3

Caso alguém esteja executando esse teste de problema, não, isso não é universalmente suportado.

Atualmente, estou testando com o Sahi Pro e é muito evidente que uma chamada http DELETE retira todos os dados do corpo fornecidos (uma grande lista de IDs a serem excluídos em massa conforme o design do terminal).

Estive em contato com eles várias vezes, bem como enviei três pacotes separados de scripts, imagens e logs para revisão e eles ainda não confirmaram isso. Um patch com falha e uma conferência perdida pelo suporte deles mais tarde e ainda não recebi uma resposta sólida.

Estou certo de que Sahi não suporta isso e imagino que muitas outras ferramentas sigam o conjunto.


É implementado na versão mais recente do Sahi Pro. Como o Sahi usa o java para fazer chamadas HTTP, o Java teve um bug anterior à versão 1.8, que não permitirá que o usuário faça uma solicitação DELETE. Portanto, com o Java 1.8 em diante e o Sahi Pro 6.1.1 (que serão publicados em breve), as pessoas podem fazer a solicitação DELETE com body em Sahi.
Vivek V Dwivedi

-1

Pode ser que o URL abaixo do GitHUb o ajude a obter a resposta. Na verdade, o Application Server como o Tomcat, Weblogic, nega a chamada HTTP.DELETE com a carga útil da solicitação. Então, mantendo tudo isso em mente, eu adicionei um exemplo no github, por favor, dê uma olhada nisso

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


-1

Consegui implementar a operação DELETE com um corpo de solicitação. Usei o AWS Lambda e o gateway de API da AWS e usei o idioma Go.


3
Eles estão falando sobre padrões, não sobre a capacidade. Você pode até ter um pedido GET com o corpo, o que não é bom
Reza
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.