Как правильно рассматривать идемпотентность с точки зрения HTTP DELETE? - PullRequest
14 голосов
/ 12 апреля 2009

В последнее время я потратил много времени на чтение спецификации HTTP 1.1 и связал ее с REST. Я обнаружил, что существует две интерпретации метода HTTP DELETE в отношении его «идемпотентности» и безопасности. Вот два лагеря:

  1. Если вы удаляете ресурс с помощью HTTP DELETE, и он успешно (200 OK), а затем вы пытаетесь удалить этот ресурс N раз, вы должны получить сообщение об успешном завершении (200 OK) для каждого и каждый из этих удаленных вызовов. Это его "идемпотентность".

  2. Если вы удаляете ресурс с помощью HTTP DELETE, и он успешно (200 OK), а затем вы пытаетесь удалить этот ресурс снова, вы должны получить сообщение об ошибке (410 Gone), поскольку ресурс был удален.

Спецификация гласит, что DELETE является идемпотентным, конечно, но также говорится, что последовательности идемпотентных событий все еще могут вызывать побочные эффекты. Я действительно чувствую, что второй лагерь правильный, а первый вводит в заблуждение. Какую «безопасность» мы ввели, позволив клиентам думать, что они стали причиной удаления ранее удаленного ресурса?

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

Ответы [ 3 ]

20 голосов
/ 12 апреля 2009

Быть идемпотентом не означает, что у запроса не должно быть побочных эффектов (это то, что описывает свойство 'safe'). Это просто означает, что выполнение одного и того же запроса несколько раз не приведет к различным или дополнительным побочным эффектам.

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

2 голосов
/ 22 октября 2012

@ MichaelBurr прав насчет идемпотентности и побочных эффектов.

Мое мнение таково, что в данном запросе REST участвуют 2 состояния: состояние клиента и состояние сервера. REST предназначен для передачи этих состояний между сервером и клиентом, так что состояние клиента отображается на подмножество состояния сервера, иными словами, подмножество остается согласованным с сервером. Из-за этого идемпотентность должна означать, что последующие идемпотентные запросы не приведут к тому, что какое-либо состояние будет отличаться от того, которое было бы при выполнении запроса только один раз. При первом УДАЛЕНИИ вы представляете, что сервер удаляет ресурс и сообщает клиенту, что он также может удалить ресурс (так как ресурс «больше не существует»). Теперь оба состояния должны быть идентичны предыдущему с минусом удаленного элемента. Чтобы клиент делал что-то другое, когда он пытается удалить элемент после того, как он уже был удален, то состояние, которое передается с сервера на клиент, должно содержать другую информацию. Сервер может делать что-то немного иначе с информацией о том, что ресурс уже удален, но как только он отвечает чем-то другим, идемпотентность методов существенно нарушается.

Для идемпотентной функции:

delete(client_state) -> client_state - {item}
delete(delete(client_state)) -> client_state - {item}
delete(client_state) = delete(delete(client_state))

Лучший способ гарантировать эту идемпотентность, если ответ сервера идентичен, то есть единственный способ для состояния клиента нарушить идемпотентность, это отсутствие неопределенности или побочные эффекты в обработке клиентом ответа ( что, вероятно, указывает на неправильную реализацию обработки ответа).

Если между клиентом и сервером существует соглашение о том, что коды состояния существуют за пределами представления передаваемого состояния (REST), то можно сообщить клиенту, что элемент «больше не существует» ( как в первом запросе) с дополнительным комментарием, который ранее был удален. Что клиент делает с этой информацией, неясно, но это не должно влиять на итоговое состояние клиента. Но тогда код состояния нельзя использовать для передачи состояния, или, скорее, если он также сообщает состояние в других ситуациях (например, может быть, «у вас нет разрешения на удаление этого элемента» или «элемент не был удален»), тогда есть некоторая введенная двусмысленность или путаница. Таким образом, вам, по крайней мере, нужна довольно веская причина для того, чтобы вносить больше путаницы в общение, если вы хотите сказать, что DELETE является идемпотентом и все еще имеет ответ сервера, зависящий от предыдущих запросов DELETE, которые идентичны.

HTTP-запросы включают методы удаления, поэтому функция может напоминать

delete(client_state) = send_delete(client_state) -> receive_delete(client_state) 
                                                 -> respond_to_delete(informative_state) 
                                                 -> handle_response(informative_state) 
                                                 -> client_state - {item} 
0 голосов
/ 15 октября 2013

Википедия определяет идемпотентность как операцию, которая:

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

Обратите внимание, что они говорят о result операции. Для меня это включает и состояние сервера и код ответа.

Спецификация HTTP немного более расплывчата по этому вопросу. Он определяет его указывает, что методы HTTP являются идемпотентными:

, если предполагаемый эффект нескольких идентичных запросов такой же, как и для одного запроса.

Если вы интерпретируете effect как result в определении Википедии, то они означают одно и то же. В любом случае я подвергаю сомнению практическую выгоду, сообщая клиентам, что ресурс уже удален.

Конечная точка: Идемпотентность определяется с точки зрения одного клиента. Как только вы начинаете вводить параллельные запросы от других клиентов, все ставки отключаются. Вы должны использовать заголовки условного обновления (например, If-Match-ETag) для таких случаев.

Для повторения: вы должны вернуть тот же код возврата, независимо от того, был ли ресурс только что удален, удален ли по предыдущему запросу или никогда не существовал вообще.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...