REST DELETE действительно идемпотент?

166

DELETE должен быть идемпотентом.

Если я УДАЛЮ http://example.com/account/123, он удалит аккаунт.

Если я сделаю это снова, я бы ожидал 404, так как аккаунт больше не существует? Что если я попытаюсь УДАЛИТЬ учетную запись, которой никогда не было?

Бен Ноланд
источник
11
В дополнение к ответам я бы предложил не слишком сосредотачиваться на идемпотентной характеристике в целом: она ничего не говорит о коммутативности и одновременных запросах. Например, N + 1 одного и того же запроса PUT «R1» должен иметь тот же эффект, но вы не знаете, сделал ли другой клиент другой запрос PUT / DELETE «R2» между вами, поэтому пока n R1 = R1 и m R2 = R2, то, где вы получаете чередующиеся запросы «R1» и «R2», не обязательно будут «выглядеть» идемпотентными, если вы будете рассматривать только одного клиента.
Бруно

Ответы:

188

Идемпотентность относится к состоянию системы после выполнения запроса


Во всех случаях (кроме вопросов об ошибках - см. Ниже) учетная запись больше не существует.

От сюда

«Методы также могут иметь свойство« идемпотентности », заключающееся в том, что ( помимо ошибок или проблем с истечением срока действия ) побочные эффекты от N> 0 идентичных запросов такие же, как и для одного запроса. Методы GET, HEAD, PUT и DELETE разделяют это свойство. Кроме того, методы OPTIONS и TRACE НЕ ДОЛЖНЫ иметь побочных эффектов и поэтому являются по своей сути идемпотентными. "


Ключевой бит присутствующих побочных эффектов при N> 0 идентичных запросов такой же, как и для одного запроса.

Было бы правильно ожидать, что код состояния будет другим, но это не влияет на основную концепцию идемпотентности - вы можете отправлять запрос более одного раза без дополнительных изменений в состоянии сервера.

Крис МакКоли
источник
3
Побочные эффекты! == состояние сервера
wprl
2
@wprl Есть дебаты о том, что на самом деле этот «побочный эффект». Это может быть «состояние сервера» или ответ клиента. leedavis81.github.io/is-a-http-delete-requests-idempotent
Алиреза
Вот аргумент, что 404 на втором УДАЛЕНИИ может фактически изменить состояние сервера: stackoverflow.com/a/45194747/317522
Пауло Мерсон
1
@PauloMerson Спасибо, лично я не думаю, что имеет значение, будет ли второй возврат 404 или 200, состояние сервера не изменилось, поэтому я доволен этим.
Крис Макколи
46

Идемпотент - это результат запроса, а не код ответа, который вы получаете.

http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.1.2 говорит:

Методы также могут обладать свойством «идемпотентности», заключающимся в том, что (кроме ошибок, связанных с ошибками или истечением срока), побочные эффекты от N> 0 идентичных запросов такие же, как и для одного запроса.

Хотя вы можете получить другой код ответа, эффект отправки N + 1 запросов DELETE на один и тот же ресурс можно считать одинаковым.

Bruno
источник
13

Важным отличием является то, что идемпотент относится к побочным эффектам , а не ко всем эффектам или реакциям. Если вы сделаете это, DELETE http://example.com/account/123то в результате учетная запись 123 будет удалена с сервера. Это единственный эффект, одно-единственное изменение состояния сервера. Теперь допустим, что вы делаете тот же DELETE http://example.com/account/123запрос еще раз, сервер будет отвечать по-другому, но его состояние такое же.

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

Янак Мина
источник
7

Из HTTP RFC :

Методы также могут обладать свойством «идемпотентности», заключающимся в том, что (кроме ошибок, связанных с ошибками или истечением срока), побочные эффекты от N> 0 идентичных запросов такие же, как и для одного запроса.

Обратите внимание, что это «побочные эффекты», а не «ответ».

fumanchu
источник
7

Да. Независимо от кода ответа.

Из последней RFC для HTTP 1.1 (выделено мое):

Идемпотентные методы отличаются тем, что запрос может повторяться автоматически, если сбой связи происходит до того, как клиент сможет прочитать ответ сервера. Например, если клиент отправляет запрос PUT и основное соединение закрывается до получения какого-либо ответа, тогда клиент может установить новое соединение и повторить идемпотентный запрос. Он знает, что повторение запроса будет иметь тот же предполагаемый эффект, даже если исходный запрос был выполнен успешно, хотя ответ может отличаться.

Это прямо говорит, что ответ может отличаться. Что еще более важно, он указывает на причину концепции: если действие идемпотентно, клиент может повторить действие, когда он сталкивается с какой-либо ошибкой, и знает, что при этом он ничего не потерпит; в противном случае клиент должен будет сделать дополнительный запрос (возможно GET), чтобы увидеть, эффективен ли предыдущий, прежде чем он безопасно повторяет действие. Пока сервер может дать такую ​​гарантию, действие идемпотентно. Цитата из другого комментария :

Вычисление идемпотентности - это надежность системы. Так как вещи могут выйти из строя (например, сбой в сети), когда обнаруживается сбой, как вы восстанавливаетесь? Самое простое восстановление - это просто сделать это снова, но это работает, только если делать это снова идемпотентно. Например discard(x), идемпотент, но pop()это не так. Это все о восстановлении ошибок.

Франклин Ю
источник
2

Я думаю то же самое, 404 - Аккаунт не существует.

Вы могли бы поспорить 400 - Bad Request. Но в смысле REST объект, который вы запросили для выполнения действия, не существует. Это переводится как 404.

Джейсон МакКрири
источник
1
Чтобы сгенерировать 400, вы должны знать, что объект раньше существовал, что очень не беспокоит.
Аннаката
1
@annakata, 400 - даже не для ресурсов, которые раньше существовали (возможно, вы имеете в виду 410 / забыли), это для плохих запросов «Запрос не может быть понят сервером из-за неправильного синтаксиса».
Бруно
3
@ Бруно - я знаю, что это значит, ОП цитировал это.
Аннаката
1
Я думаю, что 200 будет хорошо. Вы хотите, чтобы состояние сервера было таким, что учетная запись исчезла. Имеет ли значение, какой запрос на самом деле заставил его уйти? По второму запросу он все еще пропал, состояние сервера не изменилось.
Энди
2

Цитата из моего другого ответа здесь :

Исторически RFC 2616, опубликованный в 1999 году, являлся наиболее упоминаемой спецификацией HTTP 1.1. К сожалению, его описание идемпотентности было расплывчатым , что оставляет место для всех этих дискуссий. Но эти спецификации были заменены RFC 7231. Цитируется из RFC 7231, раздел 4.2.2 Идемпотентные методы , выделено мое:

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

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


ОК, так что это не идемпотентность. Но тогда может возникнуть следующий вопрос: что если мы все же решим использовать 204 в последующем УДАЛЕНИИ? Это нормально?

Хороший вопрос. Мотивация понятна: позволить клиенту по-прежнему достигать намеченного результата, не беспокоясь об обработке ошибок. Я бы сказал, что возвращение 204 в последующем DELETE - это в значительной степени безобидная «белая ложь» на стороне сервера, которая на стороне клиента не сразу скажет разницу. Вот почему есть люди, которые делают это в дикой природе, и это все еще работает. Просто имейте в виду, что такая ложь может считаться семантически странной, потому что «GET / не существует» возвращает 404, а «УДАЛИТЬ / не существовать» дает 204, в этот момент клиент обнаружит, что ваша служба не полностью соответствует раздел 6.5.4 404 не найден .

Но тогда предполагаемый путь, на который намекает RFC 7231, то есть возврат 404 при последующем УДАЛЕНИИ, не должен быть проблемой в первую очередь. Многие другие разработчики решили сделать это. Это, вероятно, потому, что любой клиент, который реализует HTTP DELETE (или любой метод HTTP, в этом отношении), не будет слепо предполагать, что результат всегда будет успешным 2xx. И затем, как только разработчик начнет рассматривать обработку ошибок, 404 Not Found будет одной из первых ошибок, которая приходит в голову. В этот момент он / она надеется сделать вывод, что для операции HTTP DELETE семантически безопасно игнорировать ошибку 404. Задача решена.

RayLuo
источник