Czy REST DELETE jest naprawdę idempotentne?

165

DELETE ma być idempotentne.

Jeśli USUWAM http://example.com/account/123 , konto zostanie usunięte.

Jeśli zrobię to ponownie, czy spodziewałbym się 404, ponieważ konto już nie istnieje? Co się stanie, jeśli spróbuję USUNĄĆ konto, które nigdy nie istniało?

Ben Noland
źródło
11
Oprócz odpowiedzi sugerowałbym, aby nie skupiać się zbytnio na idempotentnej charakterystyce w ogóle: nie mówi ona nic o przemienności i jednoczesnych żądaniach. Na przykład N + 1 tego samego żądania PUT "R1" powinno mieć ten sam efekt, ale nie wiesz, czy inny klient wykonał inne żądanie PUT / DELETE "R2" pomiędzy twoim, więc gdy n R1 = R1 im R2 = R2, coś, w którym otrzymujesz przeplatane żądania „R1” i „R2” niekoniecznie „wyglądają” idempotentnie, jeśli spojrzysz tylko na jednego klienta.
Bruno

Odpowiedzi:

188

Idempotencja odnosi się do stanu systemu po zakończeniu żądania


We wszystkich przypadkach (z wyjątkiem problemów z błędami - patrz poniżej) konto już nie istnieje.

od tutaj

„Metody mogą mieć również właściwość„ idempotencja ”, ponieważ ( poza problemami z błędami lub wygaśnięciem ) skutki uboczne N> 0 identycznych żądań są takie same, jak w przypadku pojedynczego żądania. Metody GET, HEAD, PUT i DELETE współużytkują tę właściwość. Ponadto metody OPTIONS i TRACE NIE POWINNY mieć skutków ubocznych, a więc są z natury idempotentne. "


Bit klucza, który powoduje skutki uboczne N> 0 identycznych żądań, jest taki sam, jak w przypadku pojedynczego żądania.

Mógłbyś oczekiwać, że kod statusu będzie inny, ale nie wpływa to na podstawową koncepcję idempotencji - możesz wysłać żądanie więcej niż jeden raz bez dodatkowych zmian stanu serwera.

Chris McCauley
źródło
3
Efekty uboczne! == stan serwera
wprl
2
@wprl Trwa debata na temat tego, czym naprawdę jest ten „efekt uboczny”. Może to być „stan serwera” lub odpowiedź wysłana do klienta. leedavis81.github.io/is-a-http-delete-requests-idempotent
Alireza
Oto argument, że 404 po drugim DELETE może faktycznie zmienić stan serwera: stackoverflow.com/a/45194747/317522
Paulo Merson
1
@PauloMerson Dzięki, osobiście nie ma znaczenia, czy drugi zwrot to 404 czy 200, stan serwera się nie zmienił, więc jestem z tego zadowolony.
Chris McCauley
46

Idempotent dotyczy skutku żądania, a nie kodu odpowiedzi, który otrzymujesz.

http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.1.2 mówi:

Metody mogą mieć również właściwość „idempotencja”, ponieważ (poza problemami z błędami lub wygaśnięciem) skutki uboczne N> 0 identycznych żądań są takie same jak w przypadku pojedynczego żądania.

Chociaż możesz otrzymać inny kod odpowiedzi, efekt wysłania N + 1 żądań DELETE do tego samego zasobu można uznać za taki sam.

Bruno
źródło
13

Ważną różnicą jest to, że idempotentne odnosi się do skutków ubocznych , a nie do wszystkich skutków lub reakcji. Jeśli zrobisz, DELETE http://example.com/account/123efekt jest taki, że konto 123 jest teraz usuwane z serwera. To jedyny efekt, jedyna zmiana stanu serwera. Teraz powiedzmy, że robisz to samoDELETE http://example.com/account/123 żądanie, serwer odpowie inaczej, ale jego stan jest taki sam.

To nie tak, że żądanie DELETE zdecydowało o zmianie stanu serwera w inny sposób, ponieważ brakowało konta, na przykład usunięcie innego konta lub pozostawienie dziennika błędów. Nie, możesz wywołać to samo żądanie DELETE milion razy i możesz być pewien, że serwer jest w tym samym stanie, w jakim był przy pierwszym wywołaniu .

Janac Meena
źródło
7

Z HTTP RFC :

Metody mogą mieć również właściwość „idempotencja”, ponieważ (poza problemami z błędami lub wygaśnięciem) skutki uboczne N> 0 identycznych żądań są takie same jak w przypadku pojedynczego żądania.

Zauważ, że to „skutki uboczne”, a nie „reakcja”.

fumanchu
źródło
7

Tak. Niezależnie od kodu odpowiedzi.

Z najnowszego RFC dla HTTP 1.1 (wyróżnienie moje):

Metody idempotentne są rozróżniane, ponieważ żądanie może zostać automatycznie powtórzone, jeśli wystąpi awaria komunikacji, zanim klient będzie mógł odczytać odpowiedź serwera. Na przykład, jeśli klient wyśle ​​żądanie PUT, a podstawowe połączenie zostanie zamknięte przed odebraniem jakiejkolwiek odpowiedzi, klient może ustanowić nowe połączenie i ponowić żądanie idempotentne. Wie, że powtórzenie żądania będzie miało ten sam zamierzony skutek, nawet jeśli pierwotne żądanie się powiodło, chociaż odpowiedź może się różnić.

Wyraźnie mówi, że odpowiedź może się różnić. Co ważniejsze, wskazuje na przyczynę koncepcji: jeśli akcja jest idempotentna, klient może powtórzyć akcję, gdy napotka jakikolwiek błąd i wie, że w ten sposób niczego nie zawiesi; jeśli nie, klient będzie musiał wykonać dodatkowe zapytanie (prawdopodobnie GET), aby sprawdzić, czy poprzednie jest skuteczne, zanim bezpiecznie powtórzy akcję. Dopóki serwer może dać taką gwarancję, akcja jest idempotentna. Cytat z innego komentarza :

Obliczanie idempotencji dotyczy niezawodności systemu. Skoro coś może się nie udać (np. Awaria sieci), po wykryciu awarii, jak można odzyskać? Najłatwiejszym rozwiązaniem jest po prostu zrobienie tego ponownie, ale działa to tylko wtedy, gdy zrobienie tego ponownie jest idempotentne. Np. discard(x)Jest idempotentny, ale pop()nie jest. Chodzi o usuwanie błędów.

Franklin Yu
źródło
2

Myślę tak samo, 404 - Konto nie istnieje.

Możesz argumentować, że 400 - złe żądanie. Ale w sensie REST obiekt, na którym zażądałeś wykonania akcji, nie istnieje. To przekłada się na 404.

Jason McCreary
źródło
1
Aby wygenerować 400, musisz wiedzieć, że obiekt istniał, co jest bardzo niespokojne.
annakata
1
@annakata, 400 nie dotyczy nawet zasobów, które kiedyś istniały (być może masz na myśli 410 / Gone), dotyczy złych żądań „Serwer nie mógł zrozumieć żądania ze względu na nieprawidłową składnię”.
Bruno
3
@Bruno - zdaję sobie sprawę, co to znaczy, OP zacytował to.
annakata
1
Myślę, że 200 byłoby w porządku. Chcesz, aby stan serwera wskazywał, że konto zniknęło. Czy ma znaczenie, które żądanie faktycznie go spowodowało? Nadal brakowało w drugim żądaniu, stan serwera nie zmienił się.
Andy
1

Cytat z mojej innej odpowiedzi tutaj :

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.


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 są ludzie, którzy robią to na wolności i nadal działa. Pamiętaj tylko, że takie kłamstwo można uznać za dziwne semantycznie, ponieważ „GET / non-exist” zwraca 404, ale „DELETE / non-exist” daje 204, w tym momencie klient zorientowałby się, że Twoja usługa nie jest w pełni zgodna sekcja 6.5.4 404 nie znaleziono .

Ale z drugiej strony, zamierzony sposób wskazany przez RFC 7231, tj. Zwrócenie 404 przy kolejnym DELETE, nie powinien być problemem w pierwszej kolejności. Wielu innych programistów zdecydowało się to zrobić. Jest tak prawdopodobnie dlatego, że każdy 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, mam nadzieję, wyciągnąłby wniosek, że zignorowanie błędu 404 jest semantycznie bezpieczne dla operacji HTTP DELETE. Problem rozwiązany.

RayLuo
źródło