Pattern PRG (Post/Redirect/Get) в Java
Шаблон веб проектирования PRG (Post/Redirect/Get) предотвращает повторную отправку данных. Примеры использования:
- Ввод данных пользователя
- Финансовые операции
Для пояснения проблемы двойной отправки данных возьмем картинку из википедии:
Пользователь заполняет форму и отправляет её нажимая кнопку SUBMIT. С помощью метода POST выполняется отправка этих данных (к примеру по атрибуту указанному в action в теге forward) на какую-либо страницу. Далее происходит вставка данных в БД и возврат подтверждения 2xx (например 200-«ОК»). Тут может возникнуть ситуация, что пользователь обновит страницу и данные отправятся еще раз (думаю видели сообщение «Повторите отправку формы»), т.к. браузер попытается отправить запрос предшествующий переходу на данную страницу. Отправить свой платеж повторно мало кому захочется. Вот здесь и необходим паттерн PRG.
Проблема решается разбиением запроса пользователя на несколько этапов. Первый этап (POST) отправка пользователем данных и после выполнения метода POST происходит следующее — клиент получает не 2хх статус, а 3хх (Redirect). Второй этап (Redirect) — перенаправление на нужную страницу (например «операция успешно выполнена») и теперь когда пользователь обновит страницу, то запрос (GET) уже будет не к странице с заполненной формой, а к перенаправленной странице (где обычно сообщение об статусе операции).
Важно подчеркнуть момент с перенаправлением на другую страницу и как происходит очищение данных пользователя, чтобы он не смог их отправить повторно. Рассмотрим отличия операций Forward и Redirect.
Forward
- forward выполняется внутри одного сервлета
- браузер не знает о том что происходит перенаправление и исходный URL остается неизменным
- в любом браузере при обновлении страницы просто повторится оригинальный запрос с изначальным URL (тут данные опять и отправятся)
Redirect
- redirect двухшаговый процесс, когда приложение заставляет браузер дать другой URL, отличный от оригинального
- когда браузер обновляет страницу с другим URL не происходит повторения оригинального запроса, а выполняется новый запрос (чистый) на пришедший (другой) URL
- redirect медленнее forward, т.к. требуется два запроса вместо одного
- объекты помещенные в оригинальном запросе не доступны при втором запросе
Таким образом redirect нужно использовать в случаях сохранения информации в БД. С точки зрения SQL при операциях SELECT нужно использовать forward, а для INSERT, UPDATE, DELETE — redirect.
Пример с использованием Spring MVC
Реализация шаблона проектирования PRG с использованием Spring MVC.
12