Задать вопрос

Как можно избежать повторной отправки формы на сайте при переходе назад и вперед мышью?

Приветствую.
На сайте есть простая форма: имя + возраст.
Заполняю поля, отправляю форму, редиректит на страницу подтверждения отправки формы. Нажимаю на мыше кнопку «назад», потом «вперед» — форма отправлена повторно. А еще когда возвращаюсь таким способом назад, то в форме заполнены все данные. Хотелось бы и этого избежать, т. е. чтобы форма была пустой.
Подскажите, пожалуйста то, как поправить эти два пункта.

P.S.
Да и тут (на этом сайте) то же самое — заполнена форма при шаге назад.
  • Вопрос задан
  • 802 просмотра
Подписаться 3 Простой 6 комментариев
Пригласить эксперта
Ответы на вопрос 2
Не используйте Javascript везде, где попало. Однако, решение с использованием AJAX-отправки формы отлично работает. Но пользователи, у которых Javascript отключён, могут столкнуться с неверной работой страницы. А если забыть отключить кнопку отправки пока отправляется запрос, то можно так же нарваться на повторную отправку. Поэтому, лучше всегда такое на сервере поддерживать.

Серверное решение без JS более надёжно:

Реализуем паттерн Post/Redirect/Get (PRG) плюс одноразовый уникальный токен.

- Допустим у нас форма по адресу "/form".
<form id="myForm" action="/save-data" method="post">
  <!-- ...поля... -->
  <button type="submit">Отправить</button>
</form>


- Когда сервер принимает POST запрос по адресу, по которому была отправлена форма "/save-data", он проверяет валидность данных, и ежели всё верно, то не рисует ответ с успешным успехом прямо по этому адресу, а делает серверный редирект 303 на страницу "/success". Т.е. другой адрес. Почему 303? Потому что такой редирект даёт браузеру понять, что на страницу "/save-data" нет смысла возвращаться и хранить его в истории, ведь 303 нам сказал искать контент по другому адресу.
- Это решает проблему с клавишей "F5" (обновление страницы). К тому же в истории у нас всё нормально без никакого редиректа.
- Однако кнопка назад может заставить браузер вернуться на страницу с заполненной формой "/form". И повторная отправка сработает.

Для решения этой проблемы мы вводим для каждого отображения формы специальный уникальный токен.

- При загрузке страницы с формой генерируем этот токен на сервере.
- Сохраняем токен в сессию
- Рисуем в HTML формы дополнительное невидимое поле, содержащее этот же токен.

<form id="myForm" action="/save-data" method="post">
  
  <input type="hidden" name="form_token" value="уникальное_значение_12345">
  
  <!-- ...другие поля... -->
  <button type="submit">Отправить</button>
</form>


Когда пользователь нажимает кнопку Отправить правильно, без возвратов назад, происходит следующее:

1. Сервер получает POST запрос с данными формы на "/save-data"
2. Забираем значение form_token и сравниваем его с сохранённым ранее токеном из сессии.
3. Если токены совпадают, то немедленно удаляем его из сессии. Это и есть решение.
4. Делаем редирект на страницу "/success"
5. Пользователь видит красивую зелёную галочку и сообщение об успешном успехе. Он доволен.

Если же он вернётся-таки на страницу формы через кнопку Назад, увидит там всё ту же заполненную форму с данными, и подумает, что он не отправил данные, и попробует снова отправить форму, то произойдёт следующее:

1. Сервер получает POST запрос с данными формы на "/save-data"
2. Забираем значение form_token и сравниваем его с сохранённым ранее токеном из сессии.
3. Т.к. токены не совпадают (в сессии токена нет, мы его удалили ранее), то делаем редирект на страницу "/error", где сообщаем пользователю, что он уже отправлял эту форму раньше, и всё в порядке, пусть не переживает.
4. Пользователь видит сообщение и утирает пот со лба. Он доволен.

Решение только выглядит сложным. На самом деле оно простейшее.

Очистку данных формы конечно можно делать, очищая поля формы с помощью Javascript. Но... Зачем?
Но если надо, то обрабатывайте событие 'pageshow'. Проверяйте, ежели браузер действительно загрузил страницу из bfcache, и очищаете форму. Можно еще и кнопку снова активировать, если задизаблили её раньше.

window.addEventListener('pageshow', function(event) {
  // event.persisted бывает true, когда страница загружается из bfcache
  if (event.persisted) {
    const form = document.getElementById('myForm');
    if (form) {
      form.reset(); // Сбрасываем все поля формы
      const button = form.querySelector('button[type="submit"]');
      button.disabled = false; // Убедимся, что кнопка снова активна
      console.log('Страница восстановлена из кэша. Форма сброшена.');
    }
  }
});
Ответ написан
@v__V__v
Разработчик
Отдавайте вместе со страницей после обработки post-запроса куки, показывающие, что этот пользователь эту форму уже отправлял. А в обработчике проверяйте ее наличие: нет куки - обрабатывает, есть - сообщает, что не нужно отправлять эти данные еще раз.
Автозаполнение полей формы можно запретить в параметрах тега input с помощью атрибута autocomplete="off" или autocomplete="new-password". Если по каким-то причинам это не то, что нужно, то можно повесить очищающий поля формы обработчик на страницу, как вам показали выше. А вообще, тут уже было когда-то -
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы