Czy treść jednostki jest dozwolona dla żądania HTTP DELETE?

717

Wydając żądanie HTTP DELETE, identyfikator URI żądania powinien całkowicie zidentyfikować zasób do usunięcia. Czy można jednak dodawać dodatkowe metadane jako część treści żądania?

Haacked
źródło
4
W ASP.NET WebApi 2 FromBody Parametry są ignorowane dla punktów końcowych HttpDelete.
Jenny O'Reilly,
2
Mam podobne obawy, ale moja sprawa jest inna. Chcę wysłać żądanie usunięcia partii, gdy chcę usunąć sto obiektów. Z pewnością jest to świetny wzrost wydajności dla sieci starszych niż HTTP 2.0.
Singagirl,
1
Czy były jakieś zmiany w HTTP / 2?
Jyotman Singh

Odpowiedzi:

570

Specyfikacja nie zabrania tego wyraźnie ani nie zniechęca, więc powiedziałbym, że jest dozwolony.

Microsoft widzi to w ten sam sposób (słyszę szmery na widowni), stwierdzają w artykule MSDN na temat metody DELETE ADO.NET Data Services Framework :

Jeśli żądanie DELETE zawiera treść jednostki, treść jest ignorowana [...]

Dodatkowo oto, co ma do powiedzenia RFC2616 (HTTP 1.1) w odniesieniu do żądań:

  • jednostka ciała występuje tylko wtedy, gdy komunikat ciała jest (punkt 7.2)
  • obecność treści wiadomości jest sygnalizowana przez włączenie a Content-Lengthlub Transfer-Encodingnagłówka (sekcja 4.3)
  • wiadomość ciała nie muszą być włączone gdy opis sposobu żądanie nie pozwala wysyłania podmiotowych korpus (sekcja 4.3)
  • jednostka ciała jest wyraźnie zabronione w śledzić żądania tylko, wszystkie inne typy żądań są nieograniczone (rozdział 9 i 9,8 konkretnie)

W przypadku odpowiedzi określono to:

  • czy wiadomość ciała jest wliczone zależy zarówno od metody żądania i odpowiedzi statusu (sekcja 4.3)
  • wiadomość ciała jest wyraźnie zabronione w odpowiedzi na żądania głowy (rozdział 9 i 9.4 w szczególności)
  • wiadomość ciała jest wyraźnie zabronione 1xx (informacje), 204 (bez zawartości) i 304 (niemodyfikowana) odpowiedzi (sekcja 4.3)
  • wszystkie pozostałe odpowiedzi zawierają treść wiadomości, chociaż może mieć zerową długość (sekcja 4.3)
Tomalak
źródło
7
@Jason Zdecydowanie. Możesz również użyć niestandardowych nagłówków, aby przekazać dodatkowe dane, ale dlaczego nie użyć treści żądania.
Tomalak
86
Chociaż specyfikacja nie zabrania żądania DELETE posiadania treści komunikatu, sekcja 4.3 wydaje się wskazywać, że treść powinna być ignorowana przez serwery, ponieważ nie ma „zdefiniowanej semantyki” dla DELETE -treści: „Serwer POWINIEN odczytać i przekazać treść wiadomości na każde żądanie; jeśli metoda żądania nie zawiera zdefiniowanej semantyki dla ciała encji, wówczas treść wiadomości POWINNA zostać zignorowana podczas obsługi żądania . "
Shelley,
72
Należy pamiętać, że wielu klientów nie może również wysłać USUŃ z treścią. To właśnie spaliło mnie na Androida.
Karmic Coder
1
@KarmicCoder: Great point. Więcej informacji: Wysyłanie żądania HTTP DELETE w Androidzie .
MS Dousti,
2
Dużo dyskusji na temat implementacji zmieszanych ze specyfikacją HTTP. Klienci będą wdrażać rzeczy w sposób, w jaki interpretują specyfikację, nie myl tego z jej znaczeniem. Faktem jest, że specyfikacja pozostawia to niejednoznaczne. Nie zgadzam się z interpretacją, że ponieważ nie ma zdefiniowanej semantyczności dla ciała-istoty, istnieje implikacja, że ​​należy ją zignorować. Myślę, że ludzie pracują wstecz od istniejących interpretacji klientów (Jersey, klienci testowi na Androida itp.) I próbują uzasadnić interpretację, zamiast starać się być wiernym specyfikacji. Ludzie są omylni.
Gibron
169

Najnowsza aktualizacja specyfikacji HTTP 1.1 ( RFC 7231 ) wyraźnie zezwala na treść jednostki w żądaniu DELETE:

Ładunek w komunikacie żądania DELETE nie ma zdefiniowanej semantyki; wysłanie treści ładunku na żądanie DELETE może spowodować, że niektóre istniejące implementacje odrzucą żądanie.

Grzes
źródło
3
najnowsza niezatwierdzona wersja specyfikacji usuwa to wymaganie. Ostatnia zatwierdzona wersja to wciąż RFC2616 cytowany powyżej.
BishopZ
4
Która wersja Wersja 20 nadal ma to samo brzmienie, co wersja 19, do której odsyłam powyżej: „Organy żądań DELETE nie mają zdefiniowanej semantyki. Pamiętaj, że wysłanie treści na żądanie DELETE może spowodować, że niektóre istniejące implementacje odrzucą żądanie”.
grzes
11
Sugestie w wersji 26, na które możesz zezwolić na treść: zawiera 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.więc ostrzeżenie o zgodności z poprzednimi wersjami, sugeruje, że następny standard będzie brzmiał: „tak! DELETEmoże mieć ciało`.
Pure.Krome
4
RFC 7231 sekcja 4.3.5 finalizuje język od wersji 26 z A payload within a DELETE request message has no defined semantics. Ciało jest dozwolone.
mndrix
6
Treść jest dozwolona, ​​ale nie powinna być istotna dla żądania. Nie ma absolutnie sensu z niego korzystać.
Evert
54

Niektóre wersje Tomcat i Jetty wydają się ignorować ciało jednostki, jeśli jest obecne. Co może być uciążliwe, jeśli zamierzasz je otrzymać.

evan.leonard
źródło
2
Google App Engine tworzy instancję i przekazuje pusty domyślny obiekt zamiast treści żądania.
Oliver Hausler,
Więcej informacji o Tomcat: Jak zmusić Apache Tomcat do zaakceptowania metody DELETE .
MS Dousti,
50

Jednym z powodów użycia treści w żądaniu usunięcia jest optymistyczna kontrola współbieżności.

Czytasz wersję 1 rekordu.

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

Twój kolega czyta wersję 1 rekordu.

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

Twój kolega zmienia zapis i aktualizuje bazę danych, która aktualizuje wersję do 2:

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

Próbujesz usunąć rekord:

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

Powinieneś uzyskać optymistyczny wyjątek blokady. Ponownie przeczytaj zapis, sprawdź, czy jest ważny, a może go nie usuń.

Innym powodem korzystania z niego jest usuwanie wielu rekordów jednocześnie (na przykład siatka z polami wyboru wierszy).

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

Zauważ, że każda wiadomość ma swoją własną wersję. Być może możesz określić wiele wersji przy użyciu wielu nagłówków, ale George jest to prostsze i znacznie wygodniejsze.

Działa to w Tomcat (7.0.52) i Spring MVC (4.05), prawdopodobnie także we wcześniejszych wersjach:

@RestController
public class TestController {

    @RequestMapping(value="/echo-delete", method = RequestMethod.DELETE)
    SomeBean echoDelete(@RequestBody SomeBean someBean) {
        return someBean;
    }
}
Neil McGuigan
źródło
15
Posiadanie obiektów w GET (i DELETE) wyraźnie źle znosi HTTP i REST. Istnieją inne mechanizmy radzenia sobie z kontrolą współbieżności (np. If-Modified-Since i etags).
Bruno
19
W JAKI SPOSÓB JEST JEST on źle traktowany, gdy specyfikacja nie zabrania treści w USUŃ?
Neil McGuigan
5
Ponieważ nie masz nic zrobić z ciałem. Zobacz: stackoverflow.com/a/983458/372643
Bruno
14
Jest to dokładnie ten sam problem: GET pozwala pobrać reprezentację zasobu identyfikowanego przez URI, a DELETE usuwa zasób zidentyfikowany przez URI. Użyj innego identyfikatora URI dla innych wersji, jeśli chcesz usunąć określone wersje. Identyfikator URI powinien być jedynym identyfikatorem zasobu w HTTP / REST. Użyj metadanych w nagłówkach, jeśli potrzebujesz obsługi współbieżności (np. If-Unmodified-SinceLub Etagwłaśnie do tego służą ).
Bruno,
5
Użyj nagłówka ETag zamiast pola wersji w ciele
malhal
26

Wydaje mi się, że RFC 2616 tego nie określa.

Z sekcji 4.3:

Obecność treści komunikatu w żądaniu jest sygnalizowana przez włączenie pola nagłówka Content-Length lub Transfer-Encoding do nagłówków komunikatu żądania. Ciało komunikatu NIE MOŻE być zawarte w żądaniu, jeśli specyfikacja metody żądania (sekcja 5.1.1) nie pozwala na wysyłanie ciała jednostki w żądaniach. Serwer POWINIEN czytać i przekazywać treść wiadomości na każde żądanie; jeśli metoda żądania nie obejmuje zdefiniowanej semantyki dla ciała encji, wówczas treść komunikatu POWINNA zostać zignorowana podczas obsługi żądania.

I sekcja 9.7:

Metoda DELETE żąda, aby serwer pochodzenia usunął zasób zidentyfikowany przez URI żądania. Ta metoda MOŻE zostać zastąpiona przez interwencję człowieka (lub w inny sposób) na serwerze źródłowym. Nie można zagwarantować klientowi, że operacja została wykonana, nawet jeśli kod statusu zwrócony z serwera źródłowego wskazuje, że akcja została wykonana pomyślnie. Jednak serwer NIE POWINIEN wskazywać sukcesu, chyba że w chwili udzielenia odpowiedzi zamierza usunąć zasób lub przenieść go w niedostępną lokalizację.

Pomyślna odpowiedź POWINNA wynosić 200 (OK), jeśli odpowiedź zawiera byt opisujący status, 202 (Zaakceptowana), jeśli akcja nie została jeszcze wykonana, lub 204 (Brak treści), jeśli akcja została podjęta, ale odpowiedź nie obejmuje jednostka.

Jeśli żądanie przechodzi przez pamięć podręczną, a identyfikator URI żądania identyfikuje jedną lub więcej aktualnie buforowanych jednostek, wpisy MUSZĄ być traktowane jako nieaktualne. Odpowiedzi na tę metodę nie można buforować. C

Dlatego nie jest to wyraźnie dozwolone ani zabronione, a istnieje prawdopodobieństwo, że proxy po drodze usunie treść wiadomości (chociaż POWINNA ją odczytać i przekazać dalej).

Adam Rosenfield
źródło
19

Tylko jeden do góry, jeśli podasz ciało we wniosku DELETE i używasz modułu równoważenia obciążenia HTTPS w chmurze Google, odrzuci twoje żądanie z błędem 400. Uderzyłem głową w ścianę i dowiedziałem się, że Google, z jakiegokolwiek powodu, uważa, że ​​żądanie USUŃ z ciałem jest błędnym żądaniem.

Ben Fried
źródło
1
for whatever reason- ponieważ specyfikacja tak mówi: P
Mardoxx
20
Specyfikacja nie „tak mówi”, po prostu mówi, że ciało nie jest specjalnie zdefiniowane. Jeśli nie jest zdefiniowane, a chcesz to zignorować, spoko ... śmiało i zignoruj ​​to. Ale całkowite odrzucenie wniosku wydaje się skrajne i niepotrzebne.
Ben Fried
1
Nie polegaj na niezdefiniowanym zachowaniu. To dość powszechna najlepsza praktyka.
Evert
@Evert ma jawnie niezdefiniowane zachowanie (na przykład opis w specyfikacji języka C) oraz zachowanie, które jest dozwolone, ale po prostu nieopisane. Korzystanie z treści wiadomości w DELETEtym drugim przypadku.
Alnitak
9

Warto zauważyć, że specyfikacja OpenAPI dla wersji 3.0 porzuciła obsługę metod DELETE z treścią:

patrz tutaj i tutaj dla odniesienia

Może to wpłynąć na twoją implementację, dokumentację lub korzystanie z tych interfejsów API w przyszłości.

CleverPatrick
źródło
7

Wygląda na to, że ElasticSearch używa tego: https://www.elastic.co/guide/en/elasticsearch/reference/5.x/search-request-scroll.html#_clear_scroll_api

Co oznacza, że ​​Netty to obsługuje.

Jak wspomniano w komentarzach, może już tak nie być

Sebastien Lorber
źródło
1
Jeśli używasz klienta HTTP Apache, możesz łatwo tworzyć własne wersje GET i DELETE, rozszerzając HttpEntityEnclosingRequestBase i sprawiając, że metoda getMethod () zwraca GET lub DELETE. Używamy tego do rozmowy z elasticsearch.
Jilles van Gurp
2
martwy link - świetnie. potrzebujemy więcej tych odpowiedzi na linki - nie
cottton,
3
Powiązana dokumentacja zawiera teraz tylko żądania POST, bez usuwania. Czy warto dodać notatkę do tej odpowiedzi?
dshepherd
Elasticsearch używa również treści z żądaniami GET.
Nidhin David
7

Roy Fielding na liście mailingowej HTTP wyjaśnia, że ​​na liście mailingowej http https://lists.w3.org/Archives/Public/ietf-http-wg/2020JanMar/0123.html i mówi:

Ciało GET / DELETE jest absolutnie zabronione, aby miało jakikolwiek wpływ na przetwarzanie lub interpretację wniosku

Oznacza to, że ciało nie może modyfikować zachowania serwera. Następnie dodaje:

oprócz konieczności czytania i odrzucania odebranych bajtów w celu utrzymania ramkowania wiadomości.

I wreszcie powód, dla którego nie zabraniam ciała:

Jedynym powodem, dla którego nie zabroniliśmy wysyłania treści, jest to, że prowadziłoby to do leniwych implementacji, zakładając, że żadne ciało nie zostanie wysłane.

Podczas gdy klienci mogą wysyłać treść ładunku, serwery powinny ją upuścić, a interfejsy API nie powinny definiować semantycznej treści ładunku dla tych żądań.

Roberto Polli
źródło
5

Nie jest to zdefiniowane .

Ładunek w komunikacie żądania DELETE nie ma zdefiniowanej semantyki; wysłanie treści ładunku na żądanie DELETE może spowodować, że niektóre istniejące implementacje odrzucą żądanie.
https://tools.ietf.org/html/rfc7231#page-29

Simon Jin
źródło
W szczególności RFC 7231 sekcja 4.3.5
mndrix
3
Ten dokładny cytat był już zawarty w poprzednich odpowiedziach, ta odpowiedź powinna zostać usunięta.
Madbreaks
5

Używanie DELETE z treścią jest ryzykowne ... Wolę to podejście w przypadku operacji list niż REST:

Regularne operacje

GET / objects / Pobiera wszystkie obiekty

GET / object / ID Pobiera obiekt o określonym identyfikatorze

POST / objects Dodaje nowy obiekt

PUT / object / ID Dodaje obiekt o określonym identyfikatorze, aktualizuje obiekt

DELETE / object / ID Usuwa obiekt o określonym identyfikatorze

Wszystkie akcje niestandardowe są POST

POST / objects / addList Dodaje listę lub tablicę obiektów zawartych w treści

POST / objects / deleteList Usuwa listę obiektów zawartych w ciele

POST / objects / customQuery Tworzy listę na podstawie niestandardowego zapytania w treści

Jeśli klient nie obsługuje twoich rozszerzonych operacji, może działać normalnie.

Eliezer Garza
źródło
Użycie a POSTnie jest dobrym sposobem RESTy do tworzenia nowych zasobów, ponieważ semantyka odpowiedzi POST jest niejasna, szczególnie w kontekście nagłówków lokalizacji. Zasadniczo zostawiasz HTTP za sobą i stos RPC na wierzchu. Prawidłowym „sposobem HTTP / REST” jest tworzenie zasobów za pomocą PUTw / If-None-Match: *nagłówka (lub określanie właściwych metod HTTP, patrz MKCOLitp.).
hnh
4

Nie sądzę, aby opublikowano dobrą odpowiedź na to pytanie, chociaż na temat istniejących odpowiedzi pojawiło się wiele świetnych komentarzy. Podniosę sedno tych komentarzy do nowej odpowiedzi:

Ten akapit z RFC7231 został zacytowany kilka razy, co w sumie go podsumowuje.

Ładunek w komunikacie żądania DELETE nie ma zdefiniowanej semantyki; wysłanie treści ładunku na żądanie DELETE może spowodować, że niektóre istniejące implementacje odrzucą żądanie.

W innych odpowiedziach brakowało mi implikacji. Tak, dozwolone jest dołączanie treści na DELETEżądanie, ale jest to semantycznie bez znaczenia. To tak naprawdę oznacza, że ​​wydanie DELETEżądania z treścią żądania jest semantycznie równoważne z pominięciem treści żądania.

Dołączenie treści żądania nie powinno mieć żadnego wpływu na żądanie, więc włączenie go nigdy nie ma sensu.

tl; dr: Technicznie DELETEżądanie z treścią żądania jest dozwolone, ale nigdy nie jest to przydatne.

Wynicować
źródło
2
„semantycznie bez znaczenia” nie oznacza tego samego, co „nie ma zdefiniowanej semantyki”. To pierwsze oznacza, że ​​nie może mieć żadnego znaczenia. To ostatnie oznacza po prostu, że sama RFC nie określa, czym może być ta semantyka. (Piszę RFC)
Alnitak
1
Innymi słowy, jeśli implementator API chce zdefiniować dla siebie trochę semantyki, jest to całkowicie wolny.
Alnitak
1
@Alnitak to zdecydowanie błędna interpretacja. Zgodnie z tą definicją, wszelkie treści żądania HTTP nie mają zdefiniowanej semantyki, ale DELETE i GET są specyficznie wywoływane w specyfikacji. Oto fragment z jeszcze nieopublikowanego projektu, który mówi o tym konkretnie o żądaniu GET:
Evert
1
Nie zgadzam się z tobą, że nie jest to jasne w obecnie wydanych RFC, ale jeśli mi nie wierzysz, zaprosiłbym cię, aby zapytać autorów po ich woli usunięcia i pobrania. Przekonasz się, że zgadza się z moją odpowiedzią. Podobnie jak ty, jestem również zaangażowany w prace organów normalizacyjnych i nie jestem samotną osobą, która ma opinię na temat interpretacji RFC.
Evert
2
W takim przypadku 7231 jest źle sformułowany i powinien był powiedzieć „ciało danych MUSI zostać zignorowane”. Do którego szkicu odwołujesz się powyżej?
Alnitak
3

W przypadku, gdy ktoś uruchamia się w celu przetestowania tego problemu, nie, nie jest to powszechnie obsługiwane.

Obecnie testuję z Sahi Pro i jest bardzo widoczne, że wywołanie http DELETE usuwa wszelkie dostarczone dane treści (duża lista identyfikatorów, które należy usunąć zbiorczo zgodnie z projektem punktu końcowego).

Byłem z nimi w kontakcie kilka razy, a także wysłałem w trzech osobnych paczkach skrawków, zdjęć, dzienników do przejrzenia i nadal tego nie potwierdzili. Nieudana łatka i nieodebrane połączenia konferencyjne przez ich wsparcie później, a ja wciąż nie otrzymałem solidnej odpowiedzi.

Jestem pewien, że Sahi nie obsługuje tego i wyobrażam sobie, że wiele innych narzędzi podąża za tym pakietem.

parker
źródło
Jest zaimplementowany w najnowszej wersji Sahi Pro. Ponieważ Sahi używa Java do wykonywania połączeń HTTP, a Java miała błąd przed wersją 1.8, który nie pozwalał użytkownikowi na żądanie DELETE. Tak więc od wersji Java 1.8 i Sahi Pro 6.1.1 (wkrótce będzie dostępny publicznie) ludzie mogą wysyłać żądania DELETE z treścią w Sahi.
Vivek V Dwivedi
-1

Być może poniższy adres GitHUb pomoże ci uzyskać odpowiedź. W rzeczywistości serwer aplikacji, taki jak Tomcat, Weblogic odmawia połączenia HTTP.DELETE z ładunkiem żądania. Mając to na uwadze, dodałem przykład w github, proszę spojrzeć na to

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

Ashish
źródło
-1

Udało mi się zaimplementować operację DELETE z treścią żądania. Użyłem bramy AWS Lambda i AWS API i użyłem języka Go.

Dattatray
źródło
3
Mówią o standardach, a nie o umiejętności. Możesz nawet otrzymać żądanie GET z ciałem, co nie jest dobre
ReZa