Un corps d'entité est-il autorisé pour une demande HTTP DELETE?

717

Lors de l'émission d'une requête HTTP DELETE, l'URI de la requête doit identifier complètement la ressource à supprimer. Cependant, est-il permis d'ajouter des métadonnées supplémentaires dans le cadre du corps d'entité de la demande?

Piraté
la source
4
Dans ASP.NET WebApi 2, les paramètres FromBody sont ignorés pour les points de terminaison HttpDelete.
Jenny O'Reilly
2
J'ai une préoccupation similaire, mais mon cas est différent. Je souhaite émettre une demande de suppression par lots lorsque je souhaite supprimer une centaine d'objets. Il s'agit certainement d'une excellente amélioration des performances pour les réseaux antérieurs à HTTP 2.0.
Singagirl
1
Y a-t-il eu des changements dans HTTP / 2?
Jyotman Singh

Réponses:

570

La spécification ne l'interdit ni ne la décourage explicitement, j'ai donc tendance à dire qu'elle est autorisée.

Microsoft le voit de la même manière (j'entends des murmures dans le public), ils déclarent dans l'article MSDN sur la méthode DELETE d'ADO.NET Data Services Framework :

Si une demande DELETE inclut un corps d'entité, le corps est ignoré [...]

De plus, voici ce que RFC2616 (HTTP 1.1) a à dire en ce qui concerne les demandes:

  • un corps d'entité n'est présent que lorsqu'un corps de message est présent (section 7.2)
  • la présence d'un corps de message est signalée par l'inclusion d'un Content-Lengthou d' un en - Transfer-Encodingtête (section 4.3)
  • un corps de message ne doit pas être inclus lorsque la spécification de la méthode de demande ne permet pas d'envoyer un corps d'entité (section 4.3)
  • un corps d'entité est explicitement interdit dans les demandes TRACE uniquement, tous les autres types de demandes sont sans restriction (section 9 et 9.8 en particulier)

Pour les réponses, cela a été défini:

  • l' inclusion d' un corps de message dépend à la fois de la méthode de demande et de l' état de la réponse (section 4.3)
  • un corps de message est explicitement interdit dans les réponses aux requêtes HEAD (section 9, et 9.4 en particulier)
  • un corps de message est explicitement interdit dans les réponses 1xx (informatives), 204 (pas de contenu) et 304 (non modifiées) (section 4.3)
  • toutes les autres réponses incluent un corps de message, bien qu'il puisse être de longueur nulle (section 4.3)
Tomalak
la source
7
@Jason Certainement. Vous pouvez également utiliser des en-têtes personnalisés pour transmettre des données supplémentaires, mais pourquoi ne pas utiliser le corps de la demande.
Tomalak
86
Bien que la spécification n'interdise pas les demandes DELETE d'avoir un corps de message, la section 4.3 semble indiquer que le corps doit être ignoré par les serveurs car il n'y a pas de "sémantique définie" pour les corps d'entités DELETE : "Un serveur DEVRAIT lire et transmettre un corps du message sur toute demande; si la méthode de demande n'inclut pas la sémantique définie pour un corps d'entité, alors le corps du message DEVRAIT être ignoré lors du traitement de la demande . "
shelley
72
Veuillez noter que de nombreux clients ne peuvent pas non plus envoyer de SUPPRESSION avec un corps. Cela m'a juste brûlé sur Android.
Karmic Coder
1
@KarmicCoder: Excellent point. Plus d'informations: Envoi de la demande HTTP DELETE dans Android .
MS Dousti du
2
Beaucoup de discussions sur l'implémentation mélangées avec les spécifications HTTP. Les clients mettront en œuvre les choses dans la façon dont ils interprètent la spécification, ne confondez pas cela avec le sens de la spécification. Le fait est que la spécification laisse cela ambigu. Je ne suis pas d'accord avec l'interprétation selon laquelle, comme il n'y a pas de sémantique définie pour le corps d'entité, il y a une implication qu'il devrait être ignoré. Je pense que les gens travaillent à l'envers à partir d'interprétations spécifiques aux clients qui existent (Jersey, clients de test Android, etc.) et essaient de justifier l'interprétation plutôt que d'essayer d'être fidèles aux spécifications. Les humains sont faillibles.
Gibron
169

La dernière mise à jour de la spécification HTTP 1.1 ( RFC 7231 ) autorise explicitement un corps d'entité dans une demande DELETE:

Une charge utile dans un message de demande DELETE n'a pas de sémantique définie; l'envoi d'un corps de charge utile sur une demande DELETE peut entraîner le rejet de la demande par certaines implémentations existantes.

grzes
la source
3
la dernière version non approuvée de la spécification supprime cette exigence. La dernière version approuvée est toujours la RFC2616 citée ci-dessus.
BishopZ
4
Quelle version? La version 20 a toujours le même libellé que la version 19 que j'ai liée ci-dessus: "Les corps sur les demandes DELETE n'ont pas de sémantique définie. Notez que l'envoi d'un corps sur une demande DELETE peut entraîner le rejet de la demande par certaines implémentations existantes."
grzes
11
La version 26 suggère que vous pouvez autoriser un corps: 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.il est donc livré avec un avertissement de compatibilité descendante, il suggère que la prochaine norme dira: `` oui! DELETEpeut avoir un corps ».
Pure.Krome
4
La section 4.3.5 de la RFC 7231 finalise le langage de la version 26 avec A payload within a DELETE request message has no defined semantics. Le corps est donc autorisé.
mndrix
6
Le corps est autorisé mais ne devrait pas être pertinent pour la demande. Il est absolument inutile de l'utiliser.
Evert le
55

Certaines versions de Tomcat et Jetty semblent ignorer un corps d'entité s'il est présent. Ce qui peut être gênant si vous aviez l'intention de le recevoir.

evan.leonard
la source
2
Google App Engine instancie et transmet une entité par défaut vide au lieu du corps de la demande.
Oliver Hausler du
Plus d'informations sur Tomcat: Comment faire pour qu'Apache Tomcat accepte la méthode DELETE .
MS Dousti
50

L'une des raisons d'utiliser le corps dans une demande de suppression est un contrôle de concurrence optimiste.

Vous lisez la version 1 d'un enregistrement.

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

Votre collègue lit la version 1 du dossier.

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

Votre collègue modifie l'enregistrement et met à jour la base de données, qui met à jour la version à 2:

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

Vous essayez de supprimer l'enregistrement:

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

Vous devriez obtenir une exception de verrouillage optimiste. Relisez l'enregistrement, voyez qu'il est important et ne le supprimez peut-être pas.

Une autre raison de l'utiliser est de supprimer plusieurs enregistrements à la fois (par exemple, une grille avec des cases à cocher de sélection de ligne).

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

Notez que chaque message a sa propre version. Vous pouvez peut-être spécifier plusieurs versions en utilisant plusieurs en-têtes, mais par George, c'est plus simple et beaucoup plus pratique.

Cela fonctionne dans Tomcat (7.0.52) et Spring MVC (4.05), peut-être aussi avec des versions antérieures:

@RestController
public class TestController {

    @RequestMapping(value="/echo-delete", method = RequestMethod.DELETE)
    SomeBean echoDelete(@RequestBody SomeBean someBean) {
        return someBean;
    }
}
Neil McGuigan
la source
15
Avoir des corps dans GET (et DELETE) est clairement en train de maltraiter HTTP et REST. Il existe d'autres mécanismes pour gérer le contrôle de concurrence (par exemple, If-Modified-Since et etags).
Bruno
19
Comment est-il clairement maltraité lorsque la spécification n'interdit pas le corps à SUPPRIMER?
Neil McGuigan
5
Parce que vous n'êtes pas censé faire quoi que ce soit avec le corps. Voir: stackoverflow.com/a/983458/372643
Bruno
14
Il s'agit exactement du même problème: GET vous permet de récupérer la représentation de la ressource identifiée par l'URI et DELETE supprime la ressource identifiée par l'URI. Utilisez un URI différent pour les autres versions si vous souhaitez supprimer des versions spécifiques. L'URI doit être le seul identifiant de la ressource dans HTTP / REST. Utilisez des métadonnées dans les en-têtes si vous avez besoin de gérer la concurrence (par exemple If-Unmodified-Sinceou Etag, c'est à cela qu'elles sont destinées).
Bruno
5
Utilisez l'en-tête ETag au lieu d'un champ de version dans un corps
malhal
26

Il me semble que la RFC 2616 ne le précise pas.

De la section 4.3:

La présence d'un corps de message dans une demande est signalée par l'inclusion d'un champ d'en-tête Content-Length ou Transfer-Encoding dans les en-têtes de message de la demande. Un corps de message NE DOIT PAS être inclus dans une demande si la spécification de la méthode de demande (section 5.1.1) ne permet pas d'envoyer un corps d'entité dans les demandes. Un serveur DEVRAIT lire et transmettre un corps de message sur toute demande; si la méthode de demande n'inclut pas de sémantique définie pour un corps d'entité, alors le corps du message DEVRAIT être ignoré lors du traitement de la demande.

Et l'article 9.7:

La méthode DELETE demande au serveur d'origine de supprimer la ressource identifiée par l'URI de demande. Cette méthode PEUT être remplacée par une intervention humaine (ou tout autre moyen) sur le serveur d'origine. Le client ne peut pas garantir que l'opération a été effectuée, même si le code d'état renvoyé par le serveur d'origine indique que l'action s'est terminée avec succès. Cependant, le serveur NE DEVRAIT PAS indiquer de succès sauf si, au moment où la réponse est donnée, il a l'intention de supprimer la ressource ou de la déplacer vers un emplacement inaccessible.

Une réponse réussie DEVRAIT être 200 (OK) si la réponse comprend une entité décrivant le statut, 202 (Accepté) si l'action n'a pas encore été exécutée, ou 204 (Pas de contenu) si l'action a été exécutée mais la réponse ne comprend pas une entité.

Si la demande passe par un cache et que l'URI de demande identifie une ou plusieurs entités actuellement mises en cache, ces entrées DEVRAIENT être traitées comme périmées. Les réponses à cette méthode ne peuvent pas être mises en cache.c

Il n'est donc pas explicitement autorisé ou interdit, et il est possible qu'un proxy en cours de route supprime le corps du message (bien qu'il DEVRAIT le lire et le transmettre).

Adam Rosenfield
la source
19

Attention, si vous fournissez un corps dans votre demande DELETE et que vous utilisez un équilibreur de charge Google Cloud HTTPS, il rejettera votre demande avec une erreur 400. Je me cognais la tête contre un mur et j'ai découvert que Google, pour une raison quelconque, pense qu'une demande DELETE avec un corps est une demande mal formée.

Ben Fried
la source
1
for whatever reason- parce que la spécification le dit: P
Mardoxx
20
La spécification ne le dit pas, elle dit simplement que le corps n'est pas spécifiquement défini. Si ce n'est pas défini et que vous voulez l'ignorer, cool ... allez-y et ignorez-le. Mais rejeter la demande tout de suite semble extrême et inutile.
Ben Fried
1
Ne vous fiez pas à un comportement indéfini. C'est une bonne pratique assez courante.
Evert le
@Evert, il y a un comportement explicitement indéfini (comme vous voyez le décrire dans les spécifications du langage C par exemple) et il y a un comportement autorisé mais simplement non décrit. L'utilisation d'un corps de message en DELETEest le dernier.
Alnitak
9

Il convient de noter que la spécification OpenAPI pour la version 3.0 a supprimé la prise en charge des méthodes DELETE avec un corps:

voir ici et ici pour les références

Cela peut affecter votre implémentation, votre documentation ou votre utilisation de ces API à l'avenir.

CleverPatrick
la source
7

Il semble qu'ElasticSearch utilise ceci: https://www.elastic.co/guide/en/elasticsearch/reference/5.x/search-request-scroll.html#_clear_scroll_api

Ce qui signifie que Netty soutient cela.

Comme mentionné dans les commentaires, il se peut que ce ne soit plus le cas

Sébastien Lorber
la source
1
Si vous utilisez un client http apache, vous pouvez facilement créer vos propres versions de GET et DELETE en étendant HttpEntityEnclosingRequestBase et en faisant que la méthode getMethod () renvoie GET ou DELETE. Nous l'utilisons pour parler à elasticsearch.
Jilles van Gurp
2
lien mort - super. nous avons besoin de plus de ces réponses de lien - pas
cottton
3
La documentation liée ne contient désormais que des requêtes POST, pas de SUPPRESSION. Vaut-il la peine d'ajouter une note à cette réponse?
dshepherd
Elasticsearch utilise également body avec les requêtes GET.
Nidhin David
7

Roy Fielding sur la liste de diffusion HTTP précise que sur la liste de diffusion http https://lists.w3.org/Archives/Public/ietf-http-wg/2020JanMar/0123.html et dit:

Il est absolument interdit aux organismes GET / DELETE d'avoir un quelconque impact sur le traitement ou l'interprétation de la demande

Cela signifie que le corps ne doit pas modifier le comportement du serveur. Il ajoute ensuite:

mis à part la nécessité de lire et de rejeter les octets reçus afin de maintenir le cadrage du message.

Et enfin la raison de ne pas interdire le corps:

La seule raison pour laquelle nous n'avons pas interdit l'envoi d'un corps est que cela conduirait à des implémentations paresseuses en supposant qu'aucun corps ne serait envoyé.

Ainsi, alors que les clients peuvent envoyer le corps de la charge utile, les serveurs doivent le supprimer et les API ne doivent pas définir de sémantique pour le corps de la charge utile sur ces demandes.

Roberto Polli
la source
5

Ce n'est pas défini .

Une charge utile dans un message de demande DELETE n'a pas de sémantique définie; l'envoi d'un corps de charge utile sur une demande DELETE peut entraîner le rejet de la demande par certaines implémentations existantes.
https://tools.ietf.org/html/rfc7231#page-29

Simon Jin
la source
Plus précisément, RFC 7231 section 4.3.5
mndrix
3
Cette citation exacte était déjà incluse dans les réponses précédentes, cette réponse devrait être supprimée.
Madbreaks
5

L'utilisation de DELETE avec un corps est risquée ... Je préfère cette approche pour les opérations de liste à REST:

Opérations régulières

GET / objets / Obtient tous les objets

GET / objet / ID Obtient un objet avec l'ID spécifié

POST / objets Ajoute un nouvel objet

PUT / object / ID Ajoute un objet avec l'ID spécifié, met à jour un objet

DELETE / object / ID Supprime l'objet avec l'ID spécifié

Toutes les actions personnalisées sont POST

POST / objects / addList Ajoute une liste ou un tableau d'objets inclus dans le corps

POST / objects / deleteList Supprime une liste d'objets inclus dans le corps

POST / objects / customQuery Crée une liste basée sur une requête personnalisée dans le corps

Si un client ne prend pas en charge vos opérations étendues, il peut fonctionner de manière régulière.

Eliezer Garza
la source
L'utilisation de a POSTn'est pas un bon moyen RESTy pour créer de nouvelles ressources car la sémantique des réponses POST n'est pas claire, en particulier dans le contexte des en-têtes Location. Vous laissez essentiellement HTTP derrière et empilez RPC sur le dessus. La "méthode HTTP / REST" appropriée est de créer des ressources en utilisant PUTw / l'en- If-None-Match: *tête (ou en spécifiant les méthodes HTTP appropriées, voir MKCOLetc.).
hnh
4

Je ne pense pas qu'une bonne réponse à cela ait été publiée, bien qu'il y ait eu beaucoup de bons commentaires sur les réponses existantes. Je vais lever l'essentiel de ces commentaires dans une nouvelle réponse:

Ce paragraphe de la RFC7231 a été cité à plusieurs reprises, ce qui le résume.

Une charge utile dans un message de demande DELETE n'a pas de sémantique définie; l'envoi d'un corps de charge utile sur une demande DELETE peut entraîner le rejet de la demande par certaines implémentations existantes.

Ce que j'ai manqué des autres réponses était l'implication. Oui, il est autorisé d'inclure un corps sur les DELETEdemandes, mais cela n'a pas de sens sémantique. Ce que cela signifie vraiment, c'est que l'émission d'unDELETE demande avec un corps de demande équivaut sémantiquement à ne pas inclure de corps de demande.

L'inclusion d'un corps de demande ne devrait pas avoir d'effet sur la demande, il n'y a donc aucun intérêt à l'inclure.

tl; dr: Techniquement, une DELETEdemande avec un corps de demande est autorisée, mais ce n'est jamais utile de le faire.

Evert
la source
2
"sémantiquement dénué de sens" ne signifie pas la même chose que "n'a pas de sémantique définie". Le premier signifie qu'il ne peut avoir aucun sens. Ce dernier signifie simplement que le RFC lui-même ne spécifie pas ce que pourraient être ces sémantiques. (J'écris des RFC)
Alnitak
1
En d'autres termes, si l'implémenteur d'une API souhaite définir lui-même une certaine sémantique, il est parfaitement libre de le faire.
Alnitak
1
@Alnitak c'est définitivement une mauvaise interprétation. Par cette définition, tout corps de requête HTTP n'a pas de sémantique définie, mais DELETE et GET sont spécifiquement appelés dans la spécification. Voici un extrait d'un projet encore à paraître qui en parle spécifiquement à propos de la demande GET:
Evert
1
Je ne suis pas en désaccord avec vous que cela n'est pas clair dans les RFC actuellement publiés, mais si vous ne me croyez pas, je vous invite à demander aux auteurs leur intention de supprimer et d'obtenir. Vous constaterez que cela correspond à ma réponse. Comme vous, je suis également impliqué dans des organismes de normalisation et je ne suis pas seulement une personne seule avec une opinion sur la façon dont le RFC doit être interprété.
Evert le
2
Si c'est le cas, le 7231 est mal formulé et aurait dû dire "le corps de la charge utile DOIT être ignoré". De quel projet parlez-vous ci-dessus?
Alnitak
3

Dans le cas où quelqu'un se heurte à ce test de problème, non, il n'est pas universellement pris en charge.

Je teste actuellement avec Sahi Pro et il est très évident qu'un appel http DELETE supprime toutes les données de corps fournies (une grande liste d'ID à supprimer en vrac selon la conception du point de terminaison).

J'ai été en contact avec eux plusieurs fois et j'ai envoyé trois paquets distincts de scripts, d'images et de journaux pour qu'ils les examinent et ils ne l'ont toujours pas confirmé. Un patch échoué, et une conférence téléphonique manquée par leur support plus tard et je n'ai toujours pas obtenu de réponse solide.

Je suis certain que Sahi ne supporte pas cela, et j'imagine que de nombreux autres outils suivent la suite.

Parker
la source
Il est implémenté dans la dernière version de Sahi Pro. Puisque Sahi utilise java pour faire des appels HTTP, et Java avait un bogue avant la version 1.8 qui ne permet pas à l'utilisateur de faire une demande DELETE. Ainsi, avec Java 1.8 et Sahi Pro 6.1.1 (qui sera bientôt public), les gens peuvent faire une demande DELETE avec un corps à Sahi.
Vivek V Dwivedi
-1

L'URL GitHUb ci-dessous pourrait vous aider à obtenir la réponse. En fait, Application Server comme Tomcat, Weblogic refusant l'appel HTTP.DELETE avec la charge utile de la demande. Donc, en gardant ces choses à l'esprit, j'ai ajouté un exemple dans github, veuillez jeter un œil à cela

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

Ashish
la source
-1

J'ai pu implémenter l'opération DELETE avec un corps Request. J'ai utilisé la passerelle AWS Lambda et l'API AWS et utilisé le langage Go.

Dattatray
la source
3
Ils parlent de normes, pas de capacité. Vous pouvez même avoir une demande GET avec le corps, ce qui n'est pas bon
ReZa