Sobes.tech
Middle+

L'utilisateur clique sur le bouton de paiement de 100 roubles, une requête POST est envoyée au serveur, mais aucune réponse n'arrive — délai d'attente. Comment faire pour que la réenvoi ne conduise pas à une double facturation ? Comment cette tâche est-elle résolue en frontend et dans l'architecture ?

sobes.tech IA

Réponse de l'IA

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

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

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

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