Как избежать создания нескольких одинаковых записей при повторной отправке запроса
Что проверяют
Понимаете ли вы, откуда берутся дубли (двойной клик, повтор после таймаута, ретрай клиента или прокси) и на каком уровне их реально останавливают. Для QA следом главное: как вы это протестируете и где посмотрите результат.
Как отвечать
Сначала про защиту, чтобы понимать, что проверять:
- блокировка кнопки на фронте: убирает случайный двойной клик, но не спасает от повтора запроса сетью или скриптом, поэтому одной её мало;
- ключ идемпотентности: клиент генерирует UUID на операцию и шлёт его в заголовке
Idempotency-Key, сервер запоминает ключ и на повтор возвращает прежний ответ, а не создаёт новую запись; - уникальное ограничение в базе:
UNIQUEпо бизнес-ключу (например, номер заказа) это последний рубеж, который срабатывает даже при гонке двух одновременных запросов; - семантика методов: по спецификации HTTP
GET,PUTиDELETEидемпотентны, аPOSTнет, поэтому создание черезPOSTтребует отдельной защиты; - Post/Redirect/Get для классических форм: после отправки идёт редирект, и F5 не шлёт форму повторно.
Дальше тестовая часть, она здесь важнее всего. Повторите один и тот же POST в Postman или через curl с тем же ключом и без него. Отправьте два запроса параллельно (JMeter, k6 или короткий скрипт), потому что последовательный повтор гонку не ловит. Включите медленную сеть в DevTools и кликайте по кнопке во время ожидания. Оборвите соединение сразу после отправки, чтобы проверить повтор после таймаута. Результат смотрите не только в интерфейсе, а в базе: SELECT count(*) по бизнес-ключу, и в побочных эффектах вроде писем и списаний.
Отдельно проверьте, что сервер отвечает на дубль: тем же 201 с той же записью или 409 Conflict. Оба варианта допустимы, если так записано в контракте.
Где спотыкаются
Считают, что задизейбленной кнопки достаточно. Мобильный клиент с ретраями или повтор на балансировщике её обходят.
Проверяют повтор только последовательно. Дубль чаще всего возникает при гонке, когда оба запроса одновременно прошли проверку «такой записи нет».
Смотрят только на экран. Интерфейс может показать одну запись, а в базе их две, и второе письмо клиенту уже ушло.