Middle+
Der Benutzer klickt auf die Zahlungs-Schaltfläche für 100 Rubel, eine POST-Anfrage wird an den Server gesendet, aber keine Antwort kommt — Timeout. Wie kann man sicherstellen, dass eine erneute Sendung nicht zu einer Doppelbelastung führt? Wie wird diese Aufgabe im Frontend und in der Architektur gelöst?
sobes.tech KI
Antwort von AI
Чтобы избежать двойного списания при повторной отправке запроса оплаты из-за таймаута, применяются следующие подходы:
На фронтенде:
- После первого нажатия кнопки оплаты блокировать кнопку, чтобы пользователь не мог отправить запрос повторно.
- Использовать уникальный идентификатор транзакции (например, UUID), который генерируется на клиенте и отправляется на сервер вместе с запросом. При повторной отправке с тем же ID сервер понимает, что это повтор и не создает новую оплату.
- Показывать пользователю индикатор загрузки и сообщение о том, что запрос обрабатывается.
В архитектуре и на сервере:
- Идempotency key — сервер сохраняет состояние обработки запроса с данным уникальным ключом. Если приходит повторный запрос с тем же ключом, сервер возвращает тот же результат, не создавая новую операцию.
- Транзакционность и атомарность операций в базе данных: списание средств и запись транзакции должны быть одной атомарной операцией.
Пример генерации idempotency key на фронтенде (JavaScript):
function generateIdempotencyKey() {
return crypto.randomUUID();
}
const idempotencyKey = generateIdempotencyKey();
fetch('/api/pay', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Idempotency-Key': idempotencyKey
},
body: JSON.stringify({ amount: 100 })
});
Таким образом, даже если запрос повторится из-за таймаута, сервер не спишет деньги дважды.