Что такое идемпотентные методы HTTP?

Ответ

Идемпотентные HTTP-методы — это методы, для которых многократный повтор одного и того же запроса с одинаковыми данными имеет тот же эффект на состояние сервера, что и однократный запрос. Это свойство гарантируется спецификацией HTTP и критически важно для надёжности веб-API, особенно при автоматических повторах запросов из-за сетевых неполадок.

Идемпотентные методы:

  • GET, HEAD, OPTIONS, TRACE: Запросы только для чтения. Они не изменяют состояние сервера, поэтому по определению идемпотентны.
  • PUT: Используется для полного обновления ресурса. Повторные запросы с тем же телом к одному URI должны оставлять ресурс в идентичном состоянии.
  • DELETE: Удаление ресурса. После первого успешного удаления ресурса, последующие запросы DELETE к тому же URI обычно возвращают статус 404 Not Found или 410 Gone, но общее состояние сервера (отсутствие ресурса) не меняется.

Неидемпотентный метод:

  • POST: Предназначен для создания ресурсов или выполнения действий с побочными эффектами. Каждый запрос POST может создать новый ресурс или привести к иному изменению состояния.

Пример на PHP с использованием Guzzle HTTP Client:

// Идемпотентный PUT-запрос (обновление пользователя)
$client = new GuzzleHttpClient();
$response1 = $client->put('https://api.example.com/users/123', [
    'json' => ['name' => 'Alice', 'role' => 'admin']
]);
// Если этот запрос отправить повторно из-за таймаута, это безопасно.
$response2 = $client->put('https://api.example.com/users/123', [
    'json' => ['name' => 'Alice', 'role' => 'admin']
]);
// Состояние пользователя с ID 123 после обоих запросов идентично.

// Неидемпотентный POST-запрос (создание пользователя)
$response3 = $client->post('https://api.example.com/users', [
    'json' => ['name' => 'Bob']
]); // Создаёт пользователя с ID 456
$response4 = $client->post('https://api.example.com/users', [
    'json' => ['name' => 'Bob']
]); // Создаёт ЕЩЁ ОДНОГО пользователя с ID 457 — это дублирование!

Важное уточнение: Идемпотентность относится к состоянию ресурса на сервере, а не к ответу. Сервер может логировать запросы или возвращать разные метаданные (например, дату последнего изменения), но сам целевой ресурс должен оставаться в том же состоянии.

Ответ 18+ 🔞

Слушай, давай разжую про идемпотентность в HTTP, а то народ часто путается, как будто в первый раз слышит. Это, блядь, важнейшая штука, если не хочешь, чтобы твоё API от повторных запросов накрылось медным тазом.

Короче, идемпотентный метод — это такой, который можно тыкать в сервер раз, десять или сто раз подряд, а финальное состояние системы будет таким же, как если бы ты сделал это один раз. Не больше, не меньше. Представь, что ты ставишь чашку на стол. Поставил один раз — она стоит. Тыкаешь её на то же место ещё пять раз — она всё равно просто стоит, а не множится, как кролики. Вот это и есть идемпотентность, ёпта. Доверия ебать ноль к сети, поэтому клиенты любят переотправлять запросы, если таймаут или ошибка. И если твой метод не идемпотентный — будет тебе хиросима с дубликатами данных.

Кто у нас идемпотентные парни?

  • GET, HEAD, OPTIONS, TRACE: Это просто зрители. Они пришли, посмотрели на состояние сервера и ушли. Ничего не тронули. Их можно вызывать хоть овердохуища раз — состояние не изменится.
  • PUT: Вот тут народ ошибается. PUT — это команда "положи вот это вот сюда, и чтобы было ТОЧНО так". Если ты шлёшь одно и то же тело на один и тот же URL повторно, ресурс в итоге должен быть в одинаковом состоянии. Обновил запись — ок. Отправил тот же запрос ещё раз — запись осталась с теми же данными, а не создалась новая. В этом весь смысл.
  • DELETE: Удалил ресурс — он умер. Отправил DELETE на тот же адрес второй раз — ресурс уже труп, состояние "отсутствия" не меняется. Сервер может в ответе материться (отдавать 404), но система в целом не сломается.

А кто неидемпотентный? Один, но огонь.

  • POST: А вот это, чувак, наш распиздяй. Его работа — создать что-то новое или сделать какое-то ебанько-действие. Каждый новый POST — это потенциально новый объект в базе, новый платёж, новая сущность. Отправил два одинаковых POST на создание заказа — получи, блядь, два одинаковых заказа и удивление пиздец у пользователя.

Смотри на примере, чтобы вообще всё встало на свои места:

// Идемпотентный PUT. Обновляем юзера.
$client = new GuzzleHttpClient();
$response1 = $client->put('https://api.example.com/users/123', [
    'json' => ['name' => 'Alice', 'role' => 'admin']
]);
// Допустим, ответ потерялся, и клиент отправил запрос снова. Не страшно!
$response2 = $client->put('https://api.example.com/users/123', [
    'json' => ['name' => 'Alice', 'role' => 'admin']
]);
// Юзер 'Alice' всё так же админ. Состояние то же. Всё чики-пуки.

// Неидемпотентный POST. Создаём юзера. Вот тут пиздец начинается.
$response3 = $client->post('https://api.example.com/users', [
    'json' => ['name' => 'Bob']
]); // Сервер создал Боба с ID 456 и отдал тебе.
$response4 = $client->post('https://api.example.com/users', [
    'json' => ['name' => 'Bob']
]); // Сервер, видя новый запрос, создаёт ЕЩЁ ОДНОГО Боба, но с ID 457!
// Поздравляю, у тебя теперь два Боба. **Сам от себя охуел?** Вот именно.

И главное, запомни: идемпотентность — про состояние ресурса на сервере, а не про ответы. Сервер может в логи писать каждый запрос, может в ответе время менять — это да похуй. Важно, чтобы сам ресурс (тот самый пользователь, заказ, документ) после тысячного одинакового запроса был в том же виде, что и после первого. Всё, теперь ты в теме. Не путай PUT с POST, и будет тебе счастье.