Двойной запрос с фронта - это ситуация, когда пользователь отправляет два или более одинаковых запроса на сервер. Это может произойти по разным причинам, таким как повторное нажатие кнопки или проблемы с сетью. Двойные запросы могут привести к нежелательным последствиям, таким как создание дубликатов данных или некорректное выполнение операций.
Чтобы защитить бэкенд от двойных запросов с фронта, можно использовать несколько подходов:
1. Отключение кнопки после первого нажатия: При первом нажатии на кнопку на стороне клиента, следует отключить ее для предотвращения повторного нажатия. Это можно сделать с помощью JavaScript, изменяя свойство disabled кнопки. Таким образом, пользователь не сможет выполнить повторный запрос, пока не будет разрешено.
Пример:
const button = document.querySelector('#myButton'); button.addEventListener('click', () => { // Запрещаем повторные нажатия кнопки button.disabled = true; // Выполняем запрос к серверу fetch('/api/myEndpoint') .then(response => response.json()) .then(data => { // Обрабатываем полученные данные // Разрешаем повторное нажатие кнопки button.disabled = false; }) .catch(err => { // Обрабатываем ошибку // Разрешаем повторное нажатие кнопки button.disabled = false; }); });
2. Уникальный токен запроса: При каждом запросе с фронтенда можно включать уникальный токен запроса (например, CSRF-токен) в заголовок или тело запроса. Сервер может проверить этот токен и разрешить выполнение только одного запроса с данным токеном. Если сервер получает несколько запросов с одним и тем же токеном, он может игнорировать все последующие запросы или возвращать ошибку.
Пример использования CSRF-токена с Express и пакетом csurf:
const express = require('express'); const csrf = require('csurf'); const app = express(); // Инициализация csurf const csrfProtection = csrf({ cookie: true }); // Маршрут, требующий проверку CSRF-токена app.post('/api/myEndpoint', csrfProtection, (req, res) => { // Обрабатываем запрос }); // Генерация страницы с CSRF-токеном app.get('/myPage', csrfProtection, (req, res) => { res.render('myPage', { csrfToken: req.csrfToken() }); });
3. Идемпотентные операции: Если запросы к серверу можно сделать идемпотентными - то есть обеспечить одинаковый результат, несмотря на множественное выполнение - то двойные запросы не будут вызывать проблем. Например, если запрос на обновление данных в базе данных не зависит от текущего состояния данных, то его можно безопасно выполнить несколько раз.
4. Журнал запросов: Вести журнал всех запросов, отправленных с фронтенда, и проверять каждый запрос на уникальность перед выполнением. Если запрос повторяется, сервер может игнорировать его или возвращать ошибку.
5. Ограничение частоты запросов: Реализовать ограничение частоты запросов для каждого пользователя. Например, можно использовать пакет rate-limit для ограничения числа запросов, которые пользователь может сделать за определенный период времени.
Пример использования пакета rate-limit с Express:
const express = require('express'); const rateLimit = require('express-rate-limit'); const app = express(); // Ограничение до 100 запросов в течение 1 часа для каждого IP-адреса const limiter = rateLimit({ windowMs: 60 * 60 * 1000, // 1 час max: 100, // максимальное число запросов }); // Применение ограничения ко всем запросам app.use(limiter); // Маршрут, который требует проверку ограничения app.post('/api/myEndpoint', (req, res) => { // Обрабатываем запрос });
Эти подходы можно использовать отдельно или в комбинации для обеспечения более надежной защиты бэкенда от двойных запросов с фронта. Важно применять несколько мер предосторожности и выбирать подход, наиболее подходящий для конкретного приложения.