Чи є POST ідемпотентним?
Згідно зі специфікацією HTTP, метод POST офіційно неідемпотентний. Це означає, що повторний виклик POST з тими самими даними може призвести до іншого результату.
Junior Level
Ні, POST не є ідемпотентним.
Згідно зі специфікацією HTTP, метод POST офіційно неідемпотентний. Це означає, що повторний виклик POST з тими самими даними може призвести до іншого результату.
POST = дія. Кожна дія — нова. Два натискання “Купити” = дві покупки. У серйозних системах це вирішують спеціальним ключем ідемпотентності — про нього нижче.
Чому POST не ідемпотентний?
POST зазвичай використовується для:
- Створення ресурсів:
POST /ordersстворить нове замовлення. Два виклики = два замовлення - Обробки даних:
POST /emails/sendнадішле два листи - Додавання даних: Кожен виклик додає щось нове
POST /orders → Створено замовлення #1
POST /orders → Створено замовлення #2 (інший результат!)
POST /orders → Створено замовлення #3 (ще один результат!)
Що це означає на практиці?
- POST не можна автоматично повторювати при мережевих помилках
- Кожен POST може створити новий побічний ефект
- Браузери попереджають при повторній відправці POST-форми
Middle Level
RFC 9110 і неідемпотентність POST
POST призначений для обробки даних відповідно до логіки ресурсу. Це фундаментальна особливість, яка визначає поведінку браузерів, проксі-серверів і програмістів.
Патерн PRG (Post/Redirect/Get)
Класичне рішення проблеми неідемпотентності POST у веб-інтерфейсах:
- Користувач натискає “Оплатити” (POST)
- Сервер обробляє платіж і надсилає код 303 See Other з URL сторінки успіху
- Браузер робить GET на сторінку успіху
Результат: При натисканні F5 повторюється безпечний GET, а не небезпечний POST зі списанням грошей.
POST для пошуку
Коли GET-запит занадто довгий (багато фільтрів), використовують POST /search. Технічно він ідемпотентний (тільки читання), але семантично це POST.
Реалізація ідемпотентності для POST
В Enterprise-системах (Stripe, Adyen, AWS) POST роблять ідемпотентним за допомогою Idempotency-Key:
- Клієнт генерує UUID і передає його в заголовку
- Сервер використовує Distributed Lock (Redis) за ключем
user_id + idempotency_key - Якщо запит вже в процесі —
409 Conflict - Якщо вже завершений — повертаємо збережений результат
Senior Level
Exactly-once delivery
У системах з чергами (Kafka, RabbitMQ) POST часто є точкою входу. Без ідемпотентності неможливо гарантувати “рівно одну” обробку повідомлення при повторних відправках (retries) продюсером.
Database Unique Constraints
Найдешевший спосіб забезпечити ідемпотентність POST — унікальний індекс за бізнес-ключами (наприклад, order_number). Однак це переносить логіку на рівень БД.
Патерн Idempotency-Key (деталі)
- Використовується Distributed Lock (напр. Redis) за ключем
user_id + idempotency_key - Якщо запит з таким ключем вже в процесі —
409 Conflict - Якщо вже завершений — повертаємо збережений результат (201 Created перетворюється на 200 OK при повторі)
Edge Cases
Коли неідемпотентність POST — це фіча
Коли користувач створює новий коментар, кожен POST має створити новий запис. Неідемпотентність тут — бажана поведінка, а не проблема.
POST для пошуку
Для таких випадків запропоновано метод QUERY (чернетка, поки не є стандартом). На практиці використовують POST /search.
Partial Failure
Якщо POST має створити 3 сутності, і створив лише 2? При повторі з тим самим ключем сервер має вміти “достворити” недостаюче або повернути помилку.
Діагностика і Моніторинг
- Double-Submit Detection: Моніторинг запитів з однаковим тілом від одного користувача протягом короткого вікна (500мс) допомагає виявити баги UI
- Header:
X-Retry-Count: Корисно додавати на клієнті, щоб сервер розумів, чи є POST першою спробою або результатом автоматичного ретраю - Відстежуйте кількість повторних POST-запитів — це індикатор проблем із мережею або багів на клієнті
🎯 Шпаргалка для співбесіди
Обов’язково знати:
- POST офіційно неідемпотентний за специфікацією HTTP (RFC 9110)
- Кожен POST може створити новий ресурс або побічний ефект (5 POST /orders = 5 замовлень)
- POST не можна автоматично повторювати при мережевому тайм-ауті — ризик подвійних оплат
- Патерн PRG (Post/Redirect/Get) вирішує проблему повторної відправки: POST → 303 → GET
- Idempotency-Key (UUID у заголовку) + Redis-lock роблять POST ідемпотентним
- Unique Constraints на рівні БД — найдешевший спосіб забезпечити ідемпотентність POST
- Неідемпотентність POST — це фіча, коли створюються нові коментарі, замовлення, платежі
Часті уточнюючі запитання:
- Як Stripe робить POST ідемпотентним? — Клієнт передає Idempotency-Key, сервер зберігає результат у Redis
- Що таке Exactly-Once Delivery? — Гарантія що повідомлення обробиться рівно один раз, попри повтори
- Навіщо POST /search якщо є GET? — Коли GET-URL занадто довгий для безлічі фільтрів
- Що робити при Partial Failure POST? — Сервер має вміти «достворити» недостаюче при повторі з тим самим ключем
Червоні прапорці (НЕ говорити):
- «POST можна безпечно повторювати» — це ризик подвійних операцій
- «POST ніколи не буває ідемпотентним» — можна через Idempotency-Key
- «POST /search — це порушення REST» — допустимо коли GET-URL перевищує ліміт
- «POST і PUT — одне й те саме для оновлення» — PUT замінює цілком, POST створює/обробляє
Пов’язані теми:
- [[Що таке ідемпотентність (idempotency)]]
- [[Які HTTP методи ідемпотентні]]
- [[Чому GET та DELETE ідемпотентні]]
- [[Які основні HTTP методи використовуються в REST]]
- [[Чи варто використовувати дієслова в URL]]