REST DELETE действительно идемпотент?
DELETE должен быть идемпотентом.
Если я УДАЛЮ http://example.com/account/123 он удалит аккаунт.
Если я сделаю это снова, я бы ожидал 404, так как аккаунт больше не существует? Что если я попытаюсь УДАЛИТЬ учетную запись, которой никогда не было?
6 ответов
Идемпотентность относится к состоянию системы после выполнения запроса
Во всех случаях (кроме вопросов об ошибках - см. Ниже) учетная запись больше не существует.
"Методы также могут иметь свойство" идемпотентности "в том смысле, что (кроме ошибок с ошибками или истечением срока действия) побочные эффекты от N > 0 идентичных запросов такие же, как и для одного запроса. Методы GET, HEAD, PUT и DELETE разделяют это свойство. Кроме того, методы OPTIONS и TRACE НЕ ДОЛЖНЫ иметь побочных эффектов и поэтому являются по своей сути идемпотентными. "
Ключевой бит присутствующих побочных эффектов при N > 0 идентичных запросов такой же, как и для одного запроса.
Было бы правильно ожидать, что код состояния будет другим, но это не влияет на основную концепцию идемпотентности - вы можете отправлять запрос более одного раза без дополнительных изменений в состоянии сервера.
Идемпотент о влиянии запроса, а не о коде ответа, который вы получаете.
http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html говорит:
Методы также могут иметь свойство "идемпотентности", заключающееся в том, что (кроме ошибок с ошибками или истечением срока действия) побочные эффекты от N > 0 идентичных запросов такие же, как и для одного запроса.
Хотя вы можете получить другой код ответа, эффект отправки N+1 запросов DELETE на один и тот же ресурс можно считать одинаковым.
Цитата из моего другого ответа здесь:
Исторически RFC 2616, опубликованный в 1999 году, был наиболее упоминаемой спецификацией HTTP 1.1. К сожалению, его описание идемпотентности было расплывчатым, что оставляет место для всех этих споров. Но эти спецификации были заменены RFC 7231. Цитируется из RFC 7231, раздел 4.2.2 Идемпотентные методы, выделено мной:
Метод запроса считается "идемпотентным", если предполагаемое ВЛИЯНИЕ НА СЕРВЕР нескольких идентичных запросов с этим методом такое же, как эффект для одного такого запроса. Из методов запроса, определенных в этой спецификации, методы запроса PUT, DELETE и безопасные являются идемпотентными.
Итак, в спецификациях написано, что идемпотентность - это влияние на сервер. Первый DELETE, возвращающий 204, а затем последующий DELETE, возвращающий 404, такой другой код состояния НЕ делает DELETE неидемпотентным. Использование этого аргумента для обоснования последующего возврата 204 не имеет значения.
ОК, значит, дело не в идемпотентности. Но тогда может возникнуть следующий вопрос: что, если мы все же решим использовать 204 в последующем DELETE? Это нормально?
Хороший вопрос. Мотивация понятна: позволить клиенту по-прежнему достичь желаемого результата, не беспокоясь об обработке ошибок. Я бы сказал, что возвращение 204 в последующем DELETE- это в значительной степени безобидная "белая ложь" на стороне сервера, в которой клиентская сторона не сразу заметит разницу. Вот почему есть люди, которые делают это в дикой природе, и это все еще работает. Просто имейте в виду, что такая ложь может считаться семантически странной, потому что "GET / несуществующий" возвращает 404, а "DELETE / несуществующий" дает 204, в этот момент клиент поймет, что ваш сервис не полностью соответствует раздел 6.5.4 404 Not Found.
Но тогда предполагаемый способ, намеченный RFC 7231, то есть возврат 404 при последующем DELETE, не должен быть проблемой в первую очередь. Многие другие разработчики предпочли это сделать. Вероятно, это связано с тем, что любой клиент, реализующий HTTP DELETE (или любой HTTP-метод, если на то пошло), не будет слепо предполагать, что результат всегда будет успешным 2xx. И затем, как только разработчик начнет рассматривать обработку ошибок, ошибка 404 Not Found будет одной из первых ошибок, которые приходят в голову. В этот момент он / она, надеюсь, сделает вывод, что для операции HTTP DELETE семантически безопасно игнорировать ошибку 404. Проблема решена.
Важным отличием является то, что идемпотент относится к побочным эффектам, а не ко всем эффектам или реакциям. Если вы делаете DELETE http://example.com/account/123
тогда эффект состоит в том, что учетная запись 123 теперь удалена с сервера. Это единственный эффект, единственное изменение состояния сервера. Теперь скажем, что вы делаете то же самое DELETE http://example.com/account/123
запрос снова, сервер будет реагировать по-другому, но его состояние такое же.
Это не похоже на запрос DELETE, решивший изменить состояние сервера другим способом, так как учетная запись отсутствовала, например, была удалена другая учетная запись или оставлен журнал ошибок. Нет, вы могли бы вызывать один и тот же запрос DELETE миллион раз, и вы можете быть уверены, что сервер находится в том же состоянии, в котором он был в первый раз.
Да. Независимо от кода ответа.
Из последней RFC для HTTP 1.1 (выделено мое):
Идемпотентные методы отличаются тем, что запрос может повторяться автоматически, если сбой связи происходит до того, как клиент сможет прочитать ответ сервера. Например, если клиент отправляет запрос PUT и основное соединение закрывается до получения какого-либо ответа, тогда клиент может установить новое соединение и повторить идемпотентный запрос. Он знает, что повторение запроса будет иметь тот же предполагаемый эффект, даже если исходный запрос был выполнен успешно, хотя ответ может отличаться.
Это прямо говорит, что ответ может отличаться. Что еще более важно, он указывает на причину концепции: если действие идемпотентно, клиент может повторить действие, когда он сталкивается с какой-либо ошибкой, и знает, что при этом он ничего не потерпит; если нет, клиенту придется сделать дополнительный запрос (возможно, GET
), чтобы увидеть, эффективен ли предыдущий, прежде чем безопасно повторить действие. Пока сервер может дать такую гарантию, действие идемпотентно. Цитата из другого комментария:
Вычисление идемпотентности - это надежность системы. Так как вещи могут выйти из строя (например, сбой в сети), когда обнаруживается сбой, как вы восстанавливаетесь? Самое простое восстановление состоит в том, чтобы просто сделать это снова, но это работает, только если сделать это снова идемпотентно. Например
discard(x)
идемпотентен, ноpop()
не является. Все дело в восстановлении после ошибок.
Из HTTP RFC:
Методы также могут иметь свойство "идемпотентности", заключающееся в том, что (кроме ошибок с ошибками или истечением срока действия) побочные эффекты от N > 0 идентичных запросов такие же, как и для одного запроса.
Обратите внимание, что это "побочные эффекты", а не "ответ".
Предположим, нам нужно управлять футбольными командами, представленными id, name, city.
{
id: "1",
name: "manchester united",
city : "manchester "
}
Утверждение, что Delete идемпотентно, означает, что если вы вызываете DELETE /team/1
несколько раз состояние системы не менялось (фактически первый вызов DELETE /team/1
удалить команду. Другими словами, удаление идемпотентно, потому что дублированный вызов позволяет не изменять состояние системы.
Таким же образом мы можем сказать PUT
также идемпотентно. представьте, что вы выполняете этот PUT более одного раза:
PUT /team/1
{
id: "1",
name: "liverpool",
city : "liverpool"
}
Дублированные вызовы такого запроса PUT всегда имеют одинаковый эффект (команда 1 будет Ливерпуль).
Очевидно, что GET-запросы также идемпотентны.
Я думаю то же самое, 404 - Аккаунт не существует.
Вы могли бы поспорить 400 - плохой запрос. Но в смысле REST объект, который вы запрашивали для выполнения действия, не существует. Это переводится как 404.