Sobes.tech
Middle+

A felhasználó megnyomja a 100 rublás fizetési gombot, POST-kérés kerül a szerverre, de nem érkezik válasz — timeout. Hogyan lehet megakadályozni, hogy az újraküldés duplán terhelje a felhasználót? Hogyan oldják meg ezt a feladatot a frontendben és az architektúrában?

sobes.tech MI

Válasz az MI-től

Чтобы избежать двойного списания при повторной отправке запроса оплаты из-за таймаута, применяются следующие подходы:

На фронтенде:

  • После первого нажатия кнопки оплаты блокировать кнопку, чтобы пользователь не мог отправить запрос повторно.
  • Использовать уникальный идентификатор транзакции (например, 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 })
});

Таким образом, даже если запрос повторится из-за таймаута, сервер не спишет деньги дважды.