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?
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?
Odpowiedzi:
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ń:
Content-Length
lub Transfer-Encoding
nagłówka (sekcja 4.3)W przypadku odpowiedzi określono to:
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.
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! DELETE
może mieć ciało`.
A payload within a DELETE request message has no defined semantics
. Ciało jest dozwolone.
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ć.
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;
}
}
If-Unmodified-Since
Lub Etag
właśnie do tego służą ).
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).
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.
for whatever reason
- ponieważ specyfikacja tak mówi: P
DELETE
tym drugim przypadku.
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ć
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ń.
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
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.
POST
nie 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ą PUT
w / If-None-Match: *
nagłówka (lub określanie właściwych metod HTTP, patrz MKCOL
itp.).
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.
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.
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