Почему PATCH не является ни безопасным, ни идемпотентным?

У меня проблемы с пониманием, почему PATCH небезопасен там, где PUT. Также идемпотентная часть - если я обновлю поле ресурса, разве это поле не вернет то же значение после обновления?

3 ответа

Решение

Прежде всего, PUT тоже не безопасно.

Безопасные методы - это методы HTTP, которые не изменяют ресурсы. Например, используя GET или HEAD для URL ресурса, НИКОГДА не изменяйте ресурс.

поскольку PUT request (как, впрочем, и PATCH) обновляет ресурс, поэтому он не может быть кэширован и, следовательно, не безопасен.

PUT запрос идемпотентен, хотя, или я должен сказать, PUT запрос должен быть идемпотентным.

Идемпотентный HTTP-метод - это HTTP-метод, который можно вызывать многократно без разных результатов. Не имеет значения, если метод вызывается только один раз или десять раз. Результат должен быть таким же. Опять же, это относится только к результату, а не к самому ресурсу. Этим все еще можно манипулировать (например, отметкой времени обновления, при условии, что эта информация не используется в (текущем) представлении ресурса.

Идея позади PUT Запрос, являющийся идемпотентным, заключается в том, что в случае сбоя вызова обновления ресурса клиент может повторить тот же вызов снова, не вызывая нежелательного или противоречивого состояния. PUT запросу всегда должен предшествовать GET запрос к ресурсу, и должен быть успешным, если и если только ресурс не изменился с тех пор. Для уточнения:- пройти через один из похожих ответов - Идемпотентный запрос PUT в параллельной среде

Сейчас PATCH Запрос предназначен для обновления только выборочных полей, он не предназначен для получения представления ресурса. Так что несколько звонков PATCH запрос может привести к нежелательному изменению состояния ресурса. Следовательно, это не IDEMPOTENT,

Например:- Есть ресурс Person

Запрос 1: PATCH /person/1 {'age': 10} - обновляет возраст ресурса до 10

Теперь предположим, что какой-то другой параллельный запрос изменяет состояние ресурса, скажем,

Запрос 2: PATCH /person/1 {'age': 19} - обновляет возраст ресурса до 19

Теперь, если отправит запрос 1 снова, он снова обновит возраст ресурса до 10, что приведет к нежелательному результату.

Это можно сделать идемпотентом, используя etags или If Modified Since заголовки.

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

Так почему же PATCH не идемпотент по сравнению с PUT? Это потому, что важно, как вы применяете свои изменения. Если вы хотите изменить name свойство ресурса, вы можете отправить что-то вроде {"name": "foo"} в качестве полезной нагрузки, и это действительно было бы идемпотентом, поскольку выполнение этого запроса любое количество раз дало бы один и тот же результат: ресурсы name атрибут теперь "foo".

Но PATCH гораздо более общий в том, как вы можете изменить ресурс (проверьте это определение о том, как применить патч JSON). Это также может, например, означать перемещение ресурса и выглядеть примерно так: { "op": "move", "from": "/a/b/c", "path": "/a/b/d" }, Эта операция, очевидно, не идемпотентна, поскольку повторный вызов может привести к ошибке.

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

Одно замечание по другим ответам: Идемпотентность определяется повторением операции несколько раз подряд. Сказать, что что-то не идемпотентно, потому что эффект отличается, если какая-то другая операция была выполнена между или параллельно, просто не является допустимым аргументом (в общем случае никакая операция не была бы идемпотентной, если бы это было так). Математически идемпотентное преобразование - это такое, которое дает один и тот же результат, независимо от того, как часто вы его применяете (например, вращение на 360 градусов). Конечно, два поворота на 360 градусов могут дать разные результаты, если вы примените любую другую операцию между ними.

Недавно я начал искать, является ли Patch идемпотентным или нет, и после прочтения о формате исправления JSON я понял, что если операция добавления применяется с использованием метода Patch, вполне возможно, что запрос неидемпотентен, поскольку он может добавлять новые значения в существующий ресурс, если один и тот же запрос сделан несколько раз.

{"op": "add", "path": "/ a / b / c", "value": ["foo", "bar"]}

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

From Name=John to Name=Gargantua. 

После повторного применения имя будет Gargantua, и патч не удастся, так как для изменения требуется имя "Джон".

"from Name=John"

Другие вопросы по тегам