Безпечний метод не змінює стан на сервері - лише читає. Ідемпотентний метод - повторний виклик з тими самими даними дає той самий стан сервера, що й одиночний.
| Метод | Безпечний | Ідемпотентний |
|---|---|---|
GET, HEAD, OPTIONS |
так | так |
PUT |
ні | так |
DELETE |
ні | так |
POST |
ні | ні |
PATCH |
ні | не гарантовано |
Приклади:
PUT /users/7 {"name": "Оля"}- один раз чи п'ять, результат той самий: ім'я «Оля»;DELETE /orders/42- перший виклик видаляє, наступні нічого не змінюють (відповідь може бути404, але стан однаковий);POST /orders- кожен виклик створює нове замовлення;PATCH {"balance": {"increment": 100}}- не ідемпотентний, аPATCH {"status": "paid"}- фактично ідемпотентний. Тому проPATCHкажуть «не гарантовано».
Ідемпотентність стосується стану, а не відповіді. Відповіді можуть відрізнятися (200 і потім 404 для DELETE), і updated_at може змінитися - важливо, що ефект для клієнта той самий.
Чому це важливо:
- повтори при збоях мережі. Клієнт не отримав відповіді - він не знає, чи запит виконався. Ідемпотентний запит можна безпечно повторити. Неідемпотентний - ні: повтор
POST /paymentsможе списати гроші двічі. Для таких операцій потрібен ключ ідемпотентності; - проксі, браузери, бібліотеки автоматично повторюють і попередньо завантажують безпечні запити. Якщо
GET /logoutчиGET /orders/42/deleteзмінює стан, прийде «невидимий» користувач - пошуковий робот, попереднє завантаження посилань - і виконає дію; - кешування: відповіді на безпечні методи можна кешувати.
Типові помилки:
- зміна стану в
GET(лічильники, «відмітити прочитаним», видалення за посиланням); PUT, реалізований як «додати до наявного» (тоді він не ідемпотентний);POSTдля читання з великим тілом запиту - допустимо як виняток (складний пошук), але відповідь не кешується, і повтор не очевидно безпечний.
У Laravel CSRF-захист і так не перевіряє GET/HEAD/OPTIONS - ще одна причина не змінювати стан у них.