Удаление ресурса с помощью http DELETE

124

Итак, учитывая, что глагол DELETE в Http идемпотентен, когда я отправляю следующий запрос, что должно произойти во втором (третьем, четвертом и т. Д.)?

DELETE /person/123

В первый раз ресурс удаляется, и я возвращаю 204 (успешно, нет содержимого). Должен ли я возвращать 204 при последующих звонках или 404 (не найдено)?

Крейг Уилсон
источник

Ответы:

153

Поскольку HTTP-запросы в системе без сохранения состояния должны быть независимыми, результаты одного запроса не должны зависеть от предыдущего запроса. Подумайте, что должно произойти, если два пользователя одновременно выполните DELETE на одном и том же ресурсе. Для второго запроса имеет смысл получить 404. То же самое должно быть верно, если один пользователь делает два запроса.

Я предполагаю, что использование DELETE, возвращающего два разных ответа, не кажется вам идемпотентным. Я считаю полезным думать об идемпотентных запросах как об оставлении системы в одном и том же состоянии, не обязательно с одинаковым ответом. Таким образом, независимо от того, УДАЛИТЕ ли вы существующий ресурс или попытаетесь УДАЛИТЬ ресурс, который не существует, состояние ресурса сервера будет одинаковым.

Даррел Миллер
источник
4
Спасибо. В этом много смысла. Я действительно думал об идемпотенте как о том же ответе.
Craig Wilson
4
@Craig Осторожно! В Поваренной книге Суббу полностью противоречит тому, что я только что сказал. Он говорит, что идемпотентность означает, что он должен возвращать тот же ответ. К счастью, Суббу будет на RESTFest, поэтому я собираюсь уточнить у него там.
Darrel Miller
60
Если вы УДАЛИТЕ то, чего не существует, вы должны просто вернуть 204 (даже если ресурс никогда не существовал). Клиент хотел, чтобы ресурс исчез, а он исчез. Возврат 404 раскрывает внутреннюю обработку, которая не важна для клиента, и приведет к возникновению ненужной ошибки.
Брайан
9
@DarrelMiller Я предполагаю, что ключевой концепцией здесь является то, что вы не должны использовать DELETE для проверки наличия ресурса, вы сначала должны использовать GET для этого. Затем, если ответ равен 200, вы должны выполнить DELETE; иначе даже не беспокойтесь об этом. Поэтому я думаю, что имеет смысл всегда возвращать 204 при DELETE.
manei_cc
10
@Brian RFC говорит, что он должен вести себя как rm. rmвозвращает ошибку, если ее не существует. tools.ietf.org/html/rfc7231#section-4.3.5
Дакс
32

Поваренная книга веб-сервисов RESTful - отличный ресурс для этого. Случайно его превью в Google показывает страницу об УДАЛЕНИИ (стр. 11):

Метод DELETE идемпотентен. Это означает, что сервер должен вернуть код ответа 200 (OK), даже если сервер удалил ресурс в предыдущем запросе. Но на практике реализация DELETE как идемпотентной операции требует, чтобы сервер отслеживал все удаленные ресурсы. В противном случае он может вернуть 404 (не найдено).

Ив Амселлем
источник
Да, похоже, это отличный ресурс. Тем не менее, раздел DELETE для меня не открывается (это 23-я страница, и предварительный просмотр уже отредактирован). Читали ли вы эту книгу? Вы случайно не знаете ответ на мой вопрос?
Craig Wilson
Эта книга просто необходима для создания REST (в частности, она говорит, а не на каком-либо языке).
Ив Амселлем
7
@Craig Читая поваренную книгу, вы ДОЛЖНЫ вернуть 200 OK, даже если вы уже удалили его. Однако на практике это потребует от сервера отслеживания всех удаленных ресурсов, поэтому вы МОЖЕТЕ использовать 404. Далее говорится, что из соображений безопасности может потребоваться, чтобы вы всегда возвращали 404. Страница 11.
Даррел Миллер
+1 Вторая и очень рекомендую книгу для разработки RESTful-сервисов.
Paul DelRe
18
Что ж, книга неправильная. Идемпотентность не означает, что код состояния будет таким же. Что важно, так это конечное состояние сервера.
Джулиан Решке
14

Я согласен с тем, что сказано в текущем выбранном ответе, что 2-й (и 3-й, 4-й, ...) DELETE должен получить 404 . И я заметил, что у этого ответа 143 голоса «за», но также есть противоположный комментарий, в котором 54 голоса «за», поэтому сообщество разделено на 2 лагеря примерно в соотношении 3: 1. А вот и дополнительная информация, чтобы разрешить этот давний спор.

  1. Прежде всего, давайте НЕ будем начинать с того, что думаю «я», что «вы» думаете или что думает еще один автор книги. Начнем со спецификаций HTTP, т.е. RFC 7231.

    • RFC 7231, раздел 4.3.5 DELETE упомянул только успешный ответ, который должен быть 2xx, но не сказал, что получит последующий DELETE. Так что давайте копнем глубже.
    • RFC 7231, раздел 6.5.4 404 Not Found говорит, что ответ 404 предназначен для ресурса, который не существует. Поскольку никакой конкретный http-метод (в частности, не DELETE) не вызывается для обработки в противном случае, мы можем интуитивно получить впечатление (и это справедливо), что мой запрос DELETE /some/resource/which/does/not/existдолжен привести к 404. Тогда также DELETE /some/resource/which/happened/to/be/removed/by/someone/else/five/days/agoможет быть возвращено 404 Тогда почему должно DELETE /some/resource/i/deleted/five/seconds/agoбыть иначе? «А как насчет идемпотентности ?!», я слышу, как вы это кричите. Погодите, мы собираемся заняться этим.
    • Исторически RFC 2616, опубликованный в 1999 году, был наиболее упоминаемой спецификацией HTTP 1.1. К сожалению, его описание идемпотентности было расплывчатым , что оставляет место для всех этих споров. Но эти спецификации были заменены RFC 7231. Цитируется из RFC 7231, раздел 4.2.2 Идемпотентные методы , выделено мной:

      Метод запроса считается «идемпотентным», если предполагаемое ВОЗДЕЙСТВИЕ на СЕРВЕР нескольких идентичных запросов с этим методом такое же, как эффект для одного такого запроса. Из методов запроса, определенных в этой спецификации, PUT, DELETE и безопасные методы запроса являются идемпотентными .

      Итак, в спецификациях написано, что идемпотентность - это влияние на сервер. Первый DELETE, возвращающий 204, а затем последующий DELETE, возвращающий 404, такой другой код состояния НЕ делает DELETE неидемпотентным. Использование этого аргумента для обоснования последующего возврата 204 не имеет значения.

  2. ОК, значит, дело не в идемпотентности. Но тогда может возникнуть следующий вопрос: что, если мы все же решим использовать 204 в последующем DELETE? Это нормально?

    Хороший вопрос. Мотивация понятна: позволить клиенту по-прежнему достичь желаемого результата, не беспокоясь об обработке ошибок. Я бы сказал, что возвращение 204 при последующем DELETE - это в значительной степени безобидная "белая ложь" на стороне сервера, в которой клиентская сторона не сразу заметит разницу. Вот почему около 25% людей делают это в дикой природе, и, похоже, это все еще работает. Просто имейте в виду, что такая ложь может считаться семантически странной, потому что GET /non-existвозвращает 404, но DELETE /non-existдает 204, в этот момент клиент поймет, что ваш сервис не полностью соответствует разделу 6.5.4 404 Not Found .

    Но я хочу отметить, что предполагаемый способ, на который намекает RFC 7231, то есть возврат 404 при последующем DELETE, в первую очередь не должен быть проблемой. Это сделали в 3 раза больше разработчиков, и слышали ли вы когда-нибудь о серьезных инцидентах или жалобах, вызванных тем, что клиент не может обработать ошибку 404? По-видимому, нет, и это потому, что любой достойный клиент, который реализует HTTP DELETE (или любой HTTP-метод, если на то пошло), не будет слепо предполагать, что результат всегда будет успешным 2xx. И затем, когда разработчик начнет рассматривать обработку ошибок, ошибка 404 Not Found будет одной из первых ошибок, которые приходят в голову. В этот момент он, вероятно, сделает вывод, что для операции HTTP DELETE семантически безопасно игнорировать ошибку 404. Так и сделали.

Задача решена.

RayLuo
источник
2
+1 «идемпотентность - это влияние на сервер». Дотошно ответил. Отлично сработано! Я сторонник 404 для последующих запросов DELETE.
nwayve
11

Первое УДАЛИТЬ : 200 или 204.

Последующие УДАЛЕНИЯ : 200 или 204.

Обоснование : DELETE должно быть идемпотентным. Если вы вернетесь 404 на второй DELETE, ваш ответ меняется от кода успеха к коду ошибки . Клиентская программа может предпринимать неправильные действия, исходя из предположения, что DELETE не удалось.

Пример :

  • Предположим, ваша операция DELETE является частью многоступенчатой ​​операции (или «саги»), выполняемой клиентской программой.
  • Клиентская программа может быть, например, мобильным приложением, выполняющим банковскую транзакцию.
  • Скажем, клиентская программа имеет автоматический повтор для операции DELETE (это имеет смысл, поскольку DELETE предполагается идемпотентным).
  • Допустим, первая операция DELETE была выполнена успешно, но ответ 200 потерялся на пути к клиентской программе.
  • Клиентская программа повторит УДАЛЕНИЕ.
  • Если вторая попытка возвращает 404, клиентская программа может отменить всю операцию из-за этого кода ошибки.
  • Но поскольку первое удаление DELETE выполнено на сервере успешно, система может остаться в несогласованном состоянии .
  • Если вторая попытка вернет 200 или 204, клиентская программа продолжит работу, как ожидалось.

Чтобы проиллюстрировать использование этого подхода, руководство по стилю HTTP API для PayPal содержит следующие рекомендации:

УДАЛЕНИЕ: этот метод ДОЛЖЕН возвращать код состояния 204, поскольку в большинстве случаев нет необходимости возвращать какой-либо контент, поскольку запрос состоит в удалении ресурса, и он был успешно удален.

Поскольку метод DELETE также ДОЛЖЕН быть идемпотентным, он ДОЛЖЕН возвращать 204, даже если ресурс уже был удален. Обычно потребителя API не волнует, был ли ресурс удален во время этой операции или раньше. Это также причина, по которой следует возвращать 204 вместо 404.

Пауло Мерсон
источник
1
Вопрос в том, что важно для клиента, что он удалил ресурс или что ресурс был удален. Что, если бы какой-то другой клиент удалил ресурс во время саги. Вы действительно хотите потерпеть неудачу, учитывая, что цель клиента достигнута?
Darrel Miller
1
@DarrelMiller Хорошее замечание. Что важнее, зависит от бизнес-контекста. Но в целом я бы предпочел вернуть 204 при второй попытке УДАЛИТЬ, даже если ресурс был удален другим клиентом. Я не хочу, чтобы служба перестала работать (например, 404), учитывая, что цель клиентов была достигнута.
Пауло Мерсон
2
Как уже упоминалось, идемпотентность - это не ваш код ответа, а состояние вашего сервера.
Niranjan
@Niranjan Я согласен, что идемпотентность связана с состоянием сервера, но другой код ответа может заставить клиента без необходимости изменять состояние сервера, отменяя текущую сагу.
Пауло Мерсон
@Paulo Merson, какой код вы вернете, если клиент попросит удалить элемент, который НИКОГДА не существовал? 204? или 404? Если вы всегда возвращаете 204, какой смысл проверять код возврата?
frenchone