Middle+
Korisnik pritisne dugme za plaćanje od 100 rubalja, šalje se POST zahtev na server, ali odgovor ne stiže — timeout. Kako osigurati da ponovo slanje ne dovede do duplog naplate? Kako se ovaj zadatak rešava na frontend-u i u arhitekturi?
sobes.tech АИ
Одговор од АИ
Чтобы избежать двойного списания при повторной отправке запроса оплаты из-за таймаута, применяются следующие подходы:
На фронтенде:
- После первого нажатия кнопки оплаты блокировать кнопку, чтобы пользователь не мог отправить запрос повторно.
- Использовать уникальный идентификатор транзакции (например, 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 })
});
Таким образом, даже если запрос повторится из-за таймаута, сервер не спишет деньги дважды.