Usuwanie zasobu za pomocą protokołu http DELETE

124

Tak więc, biorąc pod uwagę, że czasownik DELETE w Http jest idempotentny, kiedy wydam następujące żądanie, co powinno się stać z drugim (lub trzecim lub czwartym itd.)?

DELETE /person/123

Za pierwszym razem zasób jest usuwany i zwracam 204 (powodzenie, brak treści). Powinienem zwrócić 204 przy kolejnych rozmowach czy 404 (nie znaleziono)?

Craig Wilson
źródło

Odpowiedzi:

153

Ponieważ żądania HTTP w systemie bezstanowym powinny być niezależne, wyniki jednego żądania nie powinny być zależne od poprzedniego żądania. Zastanów się, co powinno się stać, jeśli dwóch użytkowników wykonało jednocześnie DELETE na tym samym zasobie. Sensowne jest, aby drugie żądanie otrzymało błąd 404. To samo powinno mieć miejsce, jeśli jeden użytkownik wysyła dwa żądania.

Domyślam się, że posiadanie DELETE zwracania dwóch różnych odpowiedzi nie jest dla ciebie idempotentne. Uważam, że przydatne jest myślenie o idempotentnych żądaniach jako pozostawiających system w tym samym stanie, niekoniecznie mających taką samą odpowiedź. Zatem niezależnie od tego, czy USUWASZ istniejący zasób, czy spróbujesz USUNĄĆ zasób, który nie istnieje, stan zasobu serwera jest taki sam.

Darrel Miller
źródło
4
Dziękuję Ci. To ma taki sens. Rzeczywiście myślałem, że idempotentka zwraca tę samą odpowiedź.
Craig Wilson
4
@Craig Ostrożnie! W książce kucharskiej Subbu całkowicie zaprzecza temu, co właśnie powiedziałem. Mówi, że idempotencja oznacza, że ​​powinna zwrócić tę samą odpowiedź. Na szczęście Subbu będzie na RESTFest, więc wyjaśnię z nim tam.
Darrel Miller
60
Jeśli USUŃ coś, co nie istnieje, powinieneś po prostu zwrócić 204 (nawet jeśli zasób nigdy nie istniał). Klient chciał, aby zasób zniknął i zniknął. Zwrócenie 404 ujawnia wewnętrzne przetwarzanie, które nie jest ważne dla klienta i spowoduje niepotrzebny błąd.
Brian
9
@DarrelMiller Myślę, że kluczową koncepcją jest to, że nie powinieneś używać DELETE do sprawdzania, czy zasób istnieje, najpierw użyjesz do tego GET. Następnie, jeśli odpowiedzią jest 200, wykonasz DELETE; inaczej nawet się tym nie przejmuj. Więc myślę, że sensowne jest zawsze zwracanie 204 na DELETE.
manei_cc,
10
@Brian The RFC mówi, że ma się tak zachowywać rm. rmzwraca błąd, jeśli nie istnieje. tools.ietf.org/html/rfc7231#section-4.3.5
Dax Fohl
32

Książka kucharska usług internetowych RESTful jest doskonałym źródłem informacji na ten temat. Przypadkowo jego podgląd w Google pokazuje stronę o DELETE (strona 11):

Metoda DELETE jest idempotentna. Oznacza to, że serwer musi zwrócić kod odpowiedzi 200 (OK), nawet jeśli usunął zasób w poprzednim żądaniu. Jednak w praktyce implementacja DELETE jako idempotentnej operacji wymaga od serwera śledzenia wszystkich usuniętych zasobów. W przeciwnym razie może zwrócić 404 (nie znaleziono).

yves amsellem
źródło
Tak, to wygląda na świetne źródło informacji. Jednak sekcja DELETE nie podciąga się dla mnie (jest to strona 23, a podgląd ma to redagowane). Przeczytałeś tę książkę? Znasz odpowiedź na moje pytanie?
Craig Wilson
Ta książka jest niezbędna do budowania REST (w szczególności mówi, a nie w języku).
yves amsellem
7
@Craig Czytając książkę kucharską, mówi, że POWINIENEŚ zwrócić 200 OK, nawet jeśli już ją usunąłeś. Jednak w praktyce wymagałoby to od serwera śledzenia wszystkich usuniętych zasobów, dlatego MOŻESZ użyć 404. Dalej mówi się, że obawy dotyczące bezpieczeństwa mogą wymagać, abyś zawsze zwracał 404. Strona 11.
Darrel Miller
+1 Po drugie, bardzo polecam książkę do projektowania usług RESTful.
Paul DelRe
18
Cóż, książka jest zła. Idempotencja nie oznacza, że ​​kod statusu będzie taki sam. Istotny jest ostateczny stan serwera.
Julian Reschke
14

Zgadzam się z tym, co mówi aktualnie wybrana odpowiedź, że druga (i trzecia, czwarta, ...) DELETE powinna otrzymać 404 . Zauważyłem, że odpowiedź ma 143 głosów pozytywnych, ale ma również przeciwny komentarz, który ma 54 głosów pozytywnych, więc społeczność jest podzielona na 2 obozy w stosunku mniej więcej 3: 1. Oto więcej informacji, które pozwolą rozstrzygnąć tę długą debatę.

  1. Przede wszystkim NIE zaczynajmy od tego, co „ja” myślę, co „ty” myślisz, ani co myśli inny autor książki. Zacznijmy od specyfikacji HTTP, tj. RFC 7231.

    • RFC 7231, sekcja 4.3.5 DELETE wspominał tylko, że pomyślna odpowiedź powinna być 2xx, ale nie mówiło, co otrzyma kolejne DELETE. Więc poszukajmy głębiej.
    • RFC 7231, sekcja 6.5.4 404 Not Found mówi, że odpowiedź 404 dotyczy zasobu nie istnieje. Ponieważ żadna konkretna metoda http (w szczególności nie DELETE) nie jest wywoływana, aby traktować ją w inny sposób, możemy intuicyjnie odnieść wrażenie (i słusznie), że moje żądanie DELETE /some/resource/which/does/not/existpowinno skutkować błędem 404. Wtedy DELETE /some/resource/which/happened/to/be/removed/by/someone/else/five/days/agorównie dobrze możemy również zwrócić 404 W takim razie dlaczego miałoby DELETE /some/resource/i/deleted/five/seconds/agobyć inaczej? „Ale co powiesz na idempotencję ?!”, słyszę, że tak krzyczysz. Poczekaj, zaraz się tym zajmiemy.
    • Historycznie rzecz biorąc, specyfikacja RFC 2616, opublikowana w 1999 r., Była najczęściej wymienianą specyfikacją HTTP 1.1. Niestety jego opis idempotencji był niejasny , co pozostawia miejsce na wszystkie te debaty. Ale ta specyfikacja została zastąpiona przez RFC 7231. Cytat z RFC 7231, sekcja 4.2.2 Idempotent Methods , wyróżnienie moje:

      Metoda żądania jest uważana za „idempotentną”, jeśli zamierzony WPŁYW NA SERWER wielu identycznych żądań z tą metodą jest taki sam, jak skutek dla pojedynczego takiego żądania. Spośród metod żądań zdefiniowanych w tej specyfikacji metody PUT, DELETE i bezpieczne żądania są idempotentne .

      Tak więc jest napisane w specyfikacji, idempotencja dotyczy wpływu na serwer. Pierwsze DELETE zwracające 204, a następnie DELETE zwracające 404, taki inny kod stanu NIE powoduje, że DELETE nie jest idempotentny. Użycie tego argumentu do uzasadnienia kolejnego zwrotu 204 jest po prostu nieistotne.

  2. OK, więc nie chodzi o idempotencję. Ale w takim razie pytanie uzupełniające może brzmieć, co jeśli nadal zdecydujemy się użyć 204 w kolejnym DELETE? Czy to jest w porządku?

    Dobre pytanie. Motywacja jest zrozumiała: pozwolić klientowi na osiągnięcie zamierzonego wyniku, bez martwienia się o obsługę błędów. Powiedziałbym, że zwrócenie 204 w kolejnym DELETE jest w dużej mierze nieszkodliwym „białym kłamstwem” po stronie serwera, którego strona klienta nie zauważy od razu różnicy. Dlatego około 25% ludzi robi to na wolności i wydaje się, że nadal działa. Pamiętaj tylko, że takie kłamstwo można uznać za dziwne semantycznie, ponieważ GET /non-existzwraca 404, ale DELETE /non-existdaje 204, w tym momencie klient zorientowałby się, że twoja usługa nie jest w pełni zgodna z sekcją 6.5.4 404 Not Found .

    Chcę jednak zaznaczyć, że zamierzony sposób wskazany przez RFC 7231, tj. Zwrócenie 404 przy kolejnym DELETE, nie powinien być problemem w pierwszej kolejności. 3 razy więcej programistów zdecydowało się to zrobić i czy kiedykolwiek słyszałeś poważny incydent lub skargę spowodowaną przez klienta, który nie był w stanie obsłużyć błędu 404? Prawdopodobnie nie, a to dlatego, że każdy przyzwoity klient, który implementuje HTTP DELETE (lub jakąkolwiek metodę HTTP, jeśli o to chodzi), nie założyłby ślepo, że wynik zawsze będzie pomyślny 2xx. A potem, gdy programista zacznie rozważać obsługę błędów, błąd 404 Not Found byłby jednym z pierwszych błędów, jakie przyjdą na myśl. W tym momencie prawdopodobnie wyciągnąłby wniosek, że jest semantycznie bezpieczne dla operacji HTTP DELETE zignorowanie błędu 404. I tak zrobili.

Problem rozwiązany.

RayLuo
źródło
2
+1 „Idempotencja polega na wpływie na serwer”. Skrupulatnie odpowiedział. Dobra robota! Jestem zwolennikiem 404 kolejnych żądań USUŃ.
nwayve
11

Najpierw USUŃ : 200 lub 204.

Kolejne USUNIĘCIA : 200 lub 204.

Uzasadnienie : DELETE powinno być idempotentne. Jeśli wrócisz 404 na drugi DELETE, Twoja odpowiedź zmienia się z kodem sukcesu do kodu błędu . Program klienta może podejmować niepoprawne działania przy założeniu, że DELETE nie powiodło się.

Przykład :

  • Załóżmy, że Twoja operacja DELETE jest częścią wieloetapowej operacji (lub „sagi”) wykonywanej przez program klienta.
  • Program klienta może być na przykład aplikacją mobilną wykonującą transakcję bankową.
  • Powiedzmy, że program kliencki ma automatyczną ponowną próbę wykonania operacji DELETE (ma to sens, ponieważ DELETE ma być idempotentne).
  • Powiedzmy, że pierwsze DELETE zostało wykonane pomyślnie, ale odpowiedź 200 zgubiła się w drodze do programu klienta.
  • Program klienta ponowi próbę usunięcia.
  • Jeśli druga próba zwróci 404, program klienta może anulować całą operację z powodu tego kodu błędu.
  • Ale ponieważ pierwsze DELETE zostało pomyślnie wykonane na serwerze, system może pozostać w niespójnym stanie .
  • Jeśli druga próba zwróci 200 lub 204, program klienta będzie działał zgodnie z oczekiwaniami.

Aby zilustrować zastosowanie tego podejścia, przewodnik po stylu interfejsu API protokołu HTTP dla systemu PayPal zawiera następujące wytyczne:

USUŃ: Ta metoda POWINNA zwrócić kod stanu 204, ponieważ w większości przypadków nie ma potrzeby zwracania żadnej treści, ponieważ żądanie dotyczy usunięcia zasobu i został on pomyślnie usunięty.

Ponieważ metoda DELETE MUSI być również idempotentna, POWINNA nadal zwracać 204, nawet jeśli zasób został już usunięty. Zwykle konsument API nie dba o to, czy zasób został usunięty w ramach tej operacji, czy wcześniej. Jest to również powód, dla którego należy zwrócić 204 zamiast 404.

Paulo Merson
źródło
1
Chodzi o to, co jest ważne dla klienta, że on usunięty zasób, albo że zasób został usunięty. Co by się stało, gdyby jakiś inny klient usunął zasób podczas sagi. Naprawdę chcesz przegrać, biorąc pod uwagę, że cel klienta został osiągnięty?
Darrel Miller,
1
@DarrelMiller Słuszna uwaga. Co ważniejsze, zależy od kontekstu biznesowego. Ale ogólnie wolałbym zwrócić 204 przy drugiej próbie DELETE, nawet jeśli zasób został usunięty przez innego klienta. Nie chcę, aby usługa zawiodła (tj. 404), biorąc pod uwagę, że cel klienta został osiągnięty.
Paulo Merson
2
Jak wspominali inni, idempotencja nie jest tym, czym jest twój kod odpowiedzi, to stan twojego serwera.
Niranjan
@Niranjan Zgadzam się, że idempotencja dotyczy stanu serwera, ale inny kod odpowiedzi może spowodować niepotrzebną zmianę stanu serwera przez anulowanie trwającej sagi.
Paulo Merson
@Paulo Merson jaki kod zwrócisz, jeśli klient poprosi o usunięcie pozycji, która NIGDY nie istniała? 204? czy 404? Jeśli zawsze zwracasz 204, jaki jest sens sprawdzania kodu powrotu?
frenchone