È consentito un corpo di entità per una richiesta DELETE HTTP?


717

Quando si emette una richiesta DELETE HTTP, l'URI della richiesta deve identificare completamente la risorsa da eliminare. Tuttavia, è possibile aggiungere ulteriori metadati come parte del corpo dell'entità della richiesta?


4
In ASP.NET i parametri FromBody di WebApi 2 vengono ignorati per gli endpoint HttpDelete.
Jenny O'Reilly,

2
Ho una preoccupazione simile, ma il mio caso è diverso. Voglio inviare una richiesta di eliminazione batch quando desidero eliminare centinaia di oggetti. Certamente è un grande aumento delle prestazioni per le reti pre HTTP 2.0.
Singagirl,

1
Ci sono stati cambiamenti in HTTP / 2?
Jyotman Singh,

Risposte:


570

La specifica non la proibisce o scoraggia esplicitamente, quindi tenderei a dire che è consentita.

Microsoft lo vede allo stesso modo (posso sentire mormorii tra il pubblico), affermano nell'articolo MSDN sul metodo DELETE di ADO.NET Data Services Framework :

Se una richiesta DELETE include un corpo entità, il corpo viene ignorato [...]

Inoltre, ecco cosa ha da dire RFC2616 (HTTP 1.1) in merito alle richieste:

  • un corpo-entità è presente solo quando è presente un corpo-messaggio (sezione 7.2)
  • la presenza di un corpo del messaggio è segnalata dall'inclusione di a Content-Lengtho Transfer-Encodingheader (sezione 4.3)
  • un corpo di messaggio non deve essere incluso quando la specifica del metodo di richiesta non consente l'invio di un corpo di entità (sezione 4.3)
  • un ente-entità è espressamente vietato solo nelle richieste TRACE, tutti gli altri tipi di richiesta sono senza restrizioni (sezioni 9 e 9.8 in particolare)

Per le risposte, questo è stato definito:

  • se un messaggio-corpo è incluso dipende sia richiesta di metodo e di stato di risposta (paragrafo 4.3)
  • un corpo di messaggio è esplicitamente vietato nelle risposte alle richieste HEAD (sezioni 9 e 9.4 in particolare)
  • un corpo di messaggio è esplicitamente vietato nelle risposte 1xx (informativo), 204 (nessun contenuto) e 304 (non modificato) (sezione 4.3)
  • tutte le altre risposte includono un corpo del messaggio, sebbene possa avere lunghezza zero (sezione 4.3)

7
@Jason Sicuramente. È inoltre possibile utilizzare intestazioni personalizzate per trasmettere dati aggiuntivi, ma perché non utilizzare il corpo della richiesta.
Tomalak,

86
Sebbene la specifica non proibisca alle richieste DELETE di avere un corpo del messaggio, la sezione 4.3 sembra indicare che il corpo dovrebbe essere ignorato dai server poiché non ci sono "semantiche definite" per i corpi entità DELETE : "Un server DOVREBBE leggere e inoltrare un corpo del messaggio su qualsiasi richiesta; se il metodo di richiesta non include la semantica definita per un corpo di entità, il corpo del messaggio DOVREBBE essere ignorato durante la gestione della richiesta . "
Shelley,

72
Si noti che anche molti client non sono in grado di inviare un DELETE con un corpo. Questo mi ha appena bruciato su Android.
Karmic Coder,

1
@KarmicCoder: ottimo punto. Ulteriori informazioni: Invio di una richiesta DELETE HTTP in Android .
MS Dousti,

2
Molta discussione sull'implementazione unita a specifiche HTTP. I clienti implementeranno le cose nel modo in cui interpretano le specifiche, non confonderle con il significato delle specifiche. Il fatto è che le specifiche lasciano questo ambiguo. Non sono d'accordo con l'interpretazione secondo cui, poiché non esiste una semantica definita per il corpo-entità, esiste un'implicazione che dovrebbe essere ignorata. Penso che le persone stiano lavorando all'indietro partendo da interpretazioni specifiche dei clienti (Jersey, client di test Android, ecc.) E provando a giustificare l'interpretazione piuttosto che tentare di essere fedeli alle specifiche. Gli umani sono fallibili.
Gibron,

169

L'ultimo aggiornamento della specifica HTTP 1.1 ( RFC 7231 ) consente esplicitamente un corpo di entità in una richiesta DELETE:

Un payload all'interno di un messaggio di richiesta DELETE non ha una semantica definita; l'invio di un corpo di payload su una richiesta DELETE potrebbe far sì che alcune implementazioni esistenti rifiutino la richiesta.


3
l'ultima versione non approvata delle specifiche rimuove questo requisito. L'ultima versione approvata è ancora la RFC2616 sopra citata.
BishopZ,

4
Quale versione? La versione 20 ha ancora la stessa formulazione della versione 19 che ho linkato sopra: "I corpi su richieste DELETE non hanno una semantica definita. Si noti che l'invio di un corpo su una richiesta DELETE potrebbe far sì che alcune implementazioni esistenti rifiutino la richiesta."
grzes

11
La versione 26 suggerisce che puoi consentire un 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.Quindi viene fornito con un avviso di compatibilità con le versioni precedenti, suggerisce che il prossimo standard dirà: 'sì! DELETEpuò avere un corpo ».
Pure.Krome

4
La sezione 4.3.5 di RFC 7231 finalizza la lingua dalla versione 26 con A payload within a DELETE request message has no defined semantics. Quindi il corpo è permesso.
mndrix,

6
Il corpo è autorizzato ma non dovrebbe essere pertinente alla richiesta. Non ha assolutamente senso usarlo.
Evert


50

Un motivo per utilizzare il corpo in una richiesta di eliminazione è il controllo della concorrenza ottimistico.

Hai letto la versione 1 di un record.

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

Il tuo collega legge la versione 1 del record.

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

Il collega modifica il record e aggiorna il database, che aggiorna la versione a 2:

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

Si tenta di eliminare il record:

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

Dovresti ottenere un'eccezione di blocco ottimista. Rileggi il record, vedi che è importante e forse non cancellalo.

Un altro motivo per usarlo è eliminare più record alla volta (ad esempio, una griglia con caselle di controllo per la selezione delle righe).

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

Si noti che ogni messaggio ha la sua versione. Forse puoi specificare più versioni usando più intestazioni, ma per George, questo è più semplice e molto più conveniente.

Funziona con Tomcat (7.0.52) e Spring MVC (4.05), possibilmente anche con versioni precedenti:

@RestController
public class TestController {

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

15
Avere corpi in GET (e DELETE) sta chiaramente maltrattando HTTP e REST. Esistono altri meccanismi per gestire il controllo della concorrenza (ad es. If-Modified-Since ed etags).
Bruno,

19
In che modo viene chiaramente maltrattato quando le specifiche non vietano il corpo in ELIMINA?
Neil McGuigan,

5
Perché non sei destinato a fare nulla con il corpo. Vedi: stackoverflow.com/a/983458/372643
Bruno,

14
Questo è esattamente lo stesso problema: GET consente di recuperare la rappresentazione della risorsa identificata dall'URI e DELETE elimina la risorsa identificata dall'URI. Utilizzare un URI diverso per altre versioni se si desidera eliminare versioni specifiche. L'URI dovrebbe essere l'unico identificatore della risorsa in HTTP / REST. Utilizzare i metadati nelle intestazioni se è necessario gestire la concorrenza (ad es. If-Unmodified-SinceO Etag, ecco a cosa servono).
Bruno,

5
Usa l'intestazione ETag invece di un campo versione in un corpo
malhal

26

Mi sembra che RFC 2616 non lo specifichi.

Dalla sezione 4.3:

La presenza di un corpo del messaggio in una richiesta è segnalata dall'inclusione di un campo di intestazione Content-Length o Transfer-Encoding nelle intestazioni dei messaggi della richiesta. Un corpo di messaggio NON DEVE essere incluso in una richiesta se la specifica del metodo di richiesta (sezione 5.1.1) non consente l'invio di un corpo di entità nelle richieste. Un server DOVREBBE leggere e inoltrare un corpo del messaggio su qualsiasi richiesta; se il metodo di richiesta non include la semantica definita per un corpo di entità, DOVREBBE DOVREBBE essere ignorato durante la gestione della richiesta.

E sezione 9.7:

Il metodo DELETE richiede che il server di origine elimini la risorsa identificata dall'URI di richiesta. Questo metodo può essere ignorato dall'intervento umano (o altri mezzi) sul server di origine. Non è possibile garantire al client che l'operazione sia stata eseguita, anche se il codice di stato restituito dal server di origine indica che l'azione è stata completata correttamente. Tuttavia, il server NON DOVREBBE indicare successo a meno che, al momento della risposta, non intenda eliminare la risorsa o spostarla in una posizione inaccessibile.

Una risposta corretta DOVREBBE essere 200 (OK) se la risposta include un'entità che descrive lo stato, 202 (Accettato) se l'azione non è stata ancora attuata o 204 (Nessun contenuto) se l'azione è stata attuata ma la risposta non include un'entità.

Se la richiesta passa attraverso una cache e l'URI della richiesta identifica una o più entità attualmente memorizzate nella cache, tali voci DOVREBBERO essere trattate come obsolete. Le risposte a questo metodo non sono memorizzabili nella cache. C

Quindi non è esplicitamente consentito o non consentito e c'è la possibilità che un proxy lungo la strada possa rimuovere il corpo del messaggio (anche se DOVREBBE leggerlo e inoltrarlo).


19

Solo un avvertimento, se fornisci un corpo nella tua richiesta DELETE e stai utilizzando un bilanciamento del carico HTTPS di Google cloud, rifiuterà la tua richiesta con un errore 400. Stavo sbattendo la testa contro un muro e ho scoperto che Google, per qualsiasi motivo, pensa che una richiesta DELETE con un corpo sia una richiesta non valida.


1
for whatever reason- Perché le specifiche lo dicono: P
Mardoxx,

20
La specifica non "dice così", dice solo che il corpo non è specificamente definito. Se non è definito e vuoi ignorarlo, fico ... vai avanti e ignoralo. Ma rifiutare apertamente la richiesta sembra estremo e non necessario.
Ben Fried,

1
Non fare affidamento su comportamenti indefiniti. È una best practice piuttosto comune.
Evert

@Evert c'è un comportamento esplicitamente indefinito (come vedi ad esempio nelle specifiche del linguaggio C) e c'è un comportamento che è permesso ma semplicemente non descritto. L'utilizzo di un corpo del messaggio in DELETEè il secondo.
Alnitak,

9

Vale la pena notare che la specifica OpenAPI per la versione 3.0 ha eliminato il supporto per i metodi DELETE con un corpo:

vedi qui e qui per i riferimenti

Ciò potrebbe influenzare l'implementazione, la documentazione o l'uso di queste API in futuro.


7

Sembra che ElasticSearch lo usi: https://www.elastic.co/guide/en/elasticsearch/reference/5.x/search-request-scroll.html#_clear_scroll_api

Il che significa che Netty lo supporta.

Come menzionato nei commenti, potrebbe non essere più il caso


1
Se usi il client http di apache puoi facilmente creare le tue versioni di GET e DELETE estendendo HttpEntityEnclosingRequestBase e facendo in modo che il metodo getMethod () restituisca GET o DELETE. Lo usiamo per parlare con elasticsearch.
Jilles van Gurp,

2
collegamento morto - fantastico. abbiamo bisogno di più di quelle risposte al link - non
cottton

3
La documentazione collegata ora contiene solo richieste POST, senza DELETE. Potrebbe valere la pena aggiungere una nota a questa risposta?
pastore

Elasticsearch utilizza anche body con richieste GET.
Nidhin David,

7

Roy Fielding sulla mailing list HTTP chiarisce che sulla mailing list http https://lists.w3.org/Archives/Public/ietf-http-wg/2020JanMar/0123.html e dice:

GET / DELETE è assolutamente vietato influire in alcun modo sull'elaborazione o l'interpretazione della richiesta

Ciò significa che il corpo non deve modificare il comportamento del server. Quindi aggiunge:

a parte la necessità di leggere e scartare i byte ricevuti al fine di mantenere l'inquadramento del messaggio.

E infine il motivo per non vietare il corpo:

L'unica ragione per cui non abbiamo vietato l'invio di un corpo è perché ciò porterebbe a implementazioni pigre supponendo che nessun corpo sarebbe stato inviato.

Pertanto, mentre i client possono inviare il corpo del payload, i server devono rilasciarlo e le API non devono definire una semantica per il corpo del payload su tali richieste.



5

L'uso di ELIMINA con un corpo è rischioso ... Preferisco questo approccio per le operazioni di elenco su REST:

Operazioni regolari

GET / objects / Ottiene tutti gli oggetti

GET / object / ID Ottiene un oggetto con ID specificato

POST / oggetti Aggiunge un nuovo oggetto

PUT / object / ID Aggiunge un oggetto con l'ID specificato, aggiorna un oggetto

DELETE / object / ID Elimina l'oggetto con l'ID specificato

Tutte le azioni personalizzate sono POST

POST / objects / addList Aggiunge un elenco o una matrice di oggetti inclusi nel corpo

POST / objects / deleteList Elimina un elenco di oggetti inclusi nel corpo

POST / objects / customQuery Crea un elenco basato sulla query personalizzata nel corpo

Se un client non supporta le operazioni estese, può funzionare in modo regolare.


L'uso di a POSTnon è un buon metodo RESTy per creare nuove risorse perché la semantica delle risposte POST non è chiara, specialmente nel contesto delle intestazioni di posizione. Stai essenzialmente lasciando HTTP alle spalle e impilando RPC in cima. Il "modo HTTP / REST" corretto è quello di creare risorse usando PUTw / If-None-Match: *header (o specificando i metodi HTTP corretti, vedi MKCOLecc.).
hnh

4

Non credo sia stata pubblicata una buona risposta a questo, anche se ci sono stati molti grandi commenti sulle risposte esistenti. Solleverò l'essenza di quei commenti in una nuova risposta:

Questo paragrafo da RFC7231 è stato citato alcune volte, il che lo riassume.

Un payload all'interno di un messaggio di richiesta DELETE non ha una semantica definita; l'invio di un corpo di payload su una richiesta DELETE potrebbe far sì che alcune implementazioni esistenti rifiutino la richiesta.

Quello che mi mancava dalle altre risposte era l'implicazione. Sì, è consentito includere un corpo nelle DELETErichieste, ma è semanticamente insignificante. Ciò significa veramente che l'emissione di unDELETE richiesta con un corpo di richiesta equivale semanticamente a non includere un corpo di richiesta.

L'inclusione di un corpo della richiesta non dovrebbe avere alcun effetto sulla richiesta, quindi non ha mai senso includerla.

tl; dr: tecnicamente DELETEè consentita una richiesta con un corpo di richiesta, ma non è mai utile farlo.


2
"semanticamente insignificante" non significa lo stesso di "non ha una semantica definita". Il primo significa che non può avere alcun significato. Quest'ultimo significa semplicemente che la stessa RFC non specifica quale potrebbe essere quella semantica. (Scrivo RFC)
Alnitak,

1
In altre parole, se l'implementatore di un'API desidera definire una semantica per se stesso, è perfettamente libero di farlo.
Alnitak,

1
@Alnitak questa è sicuramente una cattiva interpretazione. Con quella definizione qualsiasi corpo di richiesta HTTP non ha una semantica definita, ma DELETE e GET sono specificatamente indicati nella specifica. Ecco uno snippet di una bozza ancora da pubblicare che parla di questo in particolare sulla richiesta GET:
Evert

1
Non sono d'accordo con te sul fatto che ciò non sia chiaro nelle RFC attualmente rilasciate, ma se non mi credi, ti inviterei a chiedere agli autori il loro intento per DELETE e GET. Scoprirai che si allinea con la mia risposta. Come te, sono anche coinvolto in organismi di normalizzazione e non sono solo una persona sola con un'opinione su come interpretare la RFC.
Evert

2
In tal caso, 7231 è scarsamente formulato e avrebbe dovuto dire "il corpo del carico utile DEVE essere ignorato". A quale bozza ti riferisci sopra?
Alnitak,

3

Nel caso in cui qualcuno stia eseguendo questo test di verifica, No non è universalmente supportato.

Attualmente sto testando con Sahi Pro ed è evidente che una chiamata http DELETE elimina tutti i dati del corpo forniti (un ampio elenco di ID da eliminare in blocco secondo la progettazione dell'endpoint).

Sono stato in contatto con loro diverse volte e ho inviato tre pacchetti separati di script, immagini, registri per la loro revisione e ancora non lo hanno confermato. Una patch non riuscita e una teleconferenza persa dal loro supporto in seguito e non ho ancora ottenuto una risposta solida.

Sono certo che Sahi non lo supporta e immagino che molti altri strumenti seguano la suite.


È implementato nell'ultima versione di Sahi Pro. Poiché Sahi utilizza java per effettuare chiamate HTTP e Java aveva un bug precedente alla versione 1.8 che non consentiva all'utente di effettuare una richiesta DELETE. Quindi, con Java 1.8 in poi e Sahi Pro 6.1.1 (che presto sarà pubblico), le persone possono fare una richiesta DELETE con body in Sahi.
Vivek V Dwivedi,

-1

Potrebbe essere l'URL GitHUb di seguito ti aiuterà, per ottenere la risposta. In realtà, Application Server come Tomcat, Weblogic nega la chiamata HTTP.DELETE con payload di richiesta. Quindi, tenendo a mente tutte queste cose, ho aggiunto un esempio in Github, per favore date un'occhiata

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


-1

Sono stato in grado di implementare l'operazione ELIMINA con un corpo della richiesta. Ho usato AWS Lambda e AWS API gateway e ho usato la lingua Go.


3
Stanno parlando di standard, non di abilità. Puoi anche avere una richiesta GET con body, il che non va bene
ReZa
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.