Не используйте 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('Страница восстановлена из кэша. Форма сброшена.');
}
}
});