Ответ
Идемпотентность в контексте HTTP означает, что многократное выполнение одного и того же запроса приводит к тому же состоянию ресурса на сервере, как если бы запрос был выполнен один раз.
Идемпотентные методы:
GET
: Запрашивает представление ресурса. Не изменяет состояние сервера. Безопасен и идемпотентен.PUT
: Полностью заменяет ресурс по указанному URI. При повторном вызове с теми же данными ресурс просто будет перезаписан тем же самым содержимым, и итоговое состояние не изменится.DELETE
: Удаляет ресурс. Первый запрос удалит ресурс (изменит состояние), а все последующие будут возвращать404 Not Found
, но состояние системы (отсутствие ресурса) останется прежним.HEAD
: АналогиченGET
, но без тела ответа. Также идемпотентен.OPTIONS
: Запрашивает информацию о доступных опциях для ресурса. Не меняет состояние.
Неидемпотентные методы:
POST
: Обычно используется для создания нового дочернего ресурса. Каждый успешныйPOST
-запрос создает новую сущность. Например, отправка комментария к посту. Повторный запрос создаст дубликат комментария.
Условно идемпотентный метод:
PATCH
: Применяет частичные изменения к ресурсу. Его идемпотентность зависит от самой операции. Например,PATCH /items/1 { "op": "add", "value": 10 }
не будет идемпотентным, так как каждый вызов будет увеличивать значение на 10. АPATCH /items/1 { "op": "set", "field": "name", "value": "new_name" }
будет идемпотентным.
Пример в Go, демонстрирующий разницу:
// Предположим, у нас есть хранилище пользователей в памяти
var users = make(map[string]string)
// POST /users - Неидемпотентный
// Каждый вызов создает нового пользователя с уникальным ID
func createUser(w http.ResponseWriter, r *http.Request) {
userID := fmt.Sprintf("user-%d", time.Now().UnixNano())
users[userID] = "New User"
w.WriteHeader(http.StatusCreated)
fmt.Fprintf(w, "Created user with ID: %s", userID)
}
// PUT /users/user123 - Идемпотентный
// Сколько бы раз ни вызывался, состояние user123 будет одинаковым
func updateUser(w http.ResponseWriter, r *http.Request) {
// В реальном приложении ID будет из URL, например, с помощью gorilla/mux
userID := "user123"
users[userID] = "Updated User"
w.WriteHeader(http.StatusOK)
fmt.Fprintf(w, "User %s updated", userID)
}