Как я могу сообщить браузеру пользователя, что сделанный им POST-запрос не имеет побочных эффектов? - PullRequest
1 голос
/ 01 февраля 2020

Мне нужно добавить страницу на мой сайт, которая будет доступна через запрос POST. Запрос не имеет побочных эффектов, поэтому пользователь может безопасно использовать кнопку браузера «Refre sh» на странице. Причина, по которой он должен быть POST, а не GET, заключается в том, что объем данных, необходимых для характеристики запроса, велик (он включает в себя набор произвольно большого числа идентификаторов GUID, идентифицирующих ресурсы, с которыми нужно работать на более поздней стадии процесса).

Когда пользователь браузера обновляет страницу, которая была результатом запроса POST, браузер обычно предупреждает их о том, что форма будет повторно отправлена ​​и может вызвать повторение действия. В данном случае это не проблема, поскольку, как я уже сказал, действие по запросу этой страницы не имеет побочных эффектов. Поэтому я хочу сообщить браузеру пользователя, что такое предупреждение не должно предоставляться пользователю, если он использует функцию «Refre sh». Как я могу это сделать?

Ответы [ 3 ]

1 голос
/ 04 февраля 2020

Вы не можете запретить браузеру предупреждать пользователя о повторной отправке запроса POST.

Ссылки
Форумы Mozzila (Firefox предшественник) обсуждали функцию экстенсивно, начиная с 2002 года. Также происходит некоторое обсуждение других браузеров. Ясно, что было принято решение об обеспечении этой функции, и хотя были предложены обходные пути, они не были приняты.

Google Chrome (2008) и другие последующие браузеры также включали эту функцию.

Причины этого связаны с разницей между GET и POST в rfc2616: протокол передачи гипертекста - HTTP / 1.1 (1999).

GET

получить любую информацию, указанную в Request-URI

POST

запросить, чтобы сервер-источник принял объект, заключенный в запросе, в качестве нового подчиненного ресурса

Это означает, что пока GET запрос только извлекает данные, запрос POST каким-то образом изменяет данные. В соответствии с обсуждением на форуме Mozilla было принято решение о том, что отключение предупреждения создает больше рисков для пользователя, чем неудобство его хранения.

Решения
Вместо этого решение состоит в том, чтобы использовать сеансы для хранения данных в запросе POST и перенаправить пользователя с помощью запроса GET на URL-адрес, который просматривает данные сеанса для поиска. исходные параметры запроса.

Предполагается, что приложение на стороне сервера поддерживает сеанс и включено.

  1. Пользователь отправляет запрос POST с данными, которые генерируют указанный c результат POST /results
  2. Сервер сохраняет эти данные в сеансе с известным ключом
  3. Сервер отвечает 302 Перенаправление на выбранный URL (может быть тот же)
  4. Клиент запросит новая страница с GET-запросом GET /results
  5. Сервер идентифицирует входящий GET-запрос, запрашивающий результаты предыдущего POST-запроса, и извлекает данные из сеанса, используя известный ключ.

Если пользователь обновляет страницу, то повторяются шаги 4 и 5.

Чтобы сделать решение более надежным, данные POST могут быть назначены уникальному ключу t шляпа передается как часть пути или запроса в редиректе 302 GET /results?set=1. Это позволит просматривать и обновлять несколько разных страниц, например, на разных вкладках браузера. Необходимо учитывать, что уникальный ключ действителен и не разрешает доступ к другим данным сеанса.

Некоторые системы, Kibana, Grafana, pastebin.com и многие другие go на шаг вперед. Значения запроса POST хранятся в постоянном хранилище данных, и пользователю предоставляется уникальный короткий URL-адрес. Короткий URL-адрес может использоваться в запросах GET и передаваться другим пользователям для просмотра того же результата, что первоначально был запросом POST.

1 голос
/ 05 февраля 2020

Вы не можете запретить всем браузерам показывать это "Вы уверены, что хотите повторно отправить эту форму?" всплывающее окно, когда пользователь обновляет страницу, которая является результатом запроса POST. Поэтому вам нужно будет превратить этот запрос POST в запрос GET, если вы хотите запретить это всплывающее окно, когда ваши пользователи нажимают клавишу F5 на этой странице.

И для формы поиска, для которой вы вроде бы признали, что превращение POST в GET имеет свои проблемы.

Для начала, вы уверены, что вам нужно POST для начала? Действительно ли данные слишком велики для размещения в строке запроса? Принимая разумный предел в 1024 символа , составляющий около 30 GUID (дайте или возьмите некоторое пространство для повторного &q=), зачем вам сначала нужно, чтобы параметры поиска были GUID? Если вы можете сопоставить их или найти их каким-либо образом, вы можете ограничить размер каждого параметра несколькими символами вместо 32 для не пунктирного идентификатора GUID, а с 5 символами на ключ вы можете внезапно уместить 200 параметров в запросе. строка.

Все еще недостаточно? Тогда вам действительно нужен POST.

Один из упомянутых в комментариях подходов использует AJAX, поэтому ваша поисковая форма фактически не отправляет, а вместо этого отправляет данные запроса в фоновом режиме через * 1088. * HTTP POST запрос и обновляет страницу с результатами. Преимущество в том, что обновление страницы не вызывает запроса, поскольку браузер имеет только GET, но есть один недостаток: результаты поиска не получают уникальный URL, поэтому вы не можете кэшировать , добавьте в закладки или поделитесь их.

Если вас не волнует кэширование или создание закладок URL, тогда AJAX определенно является самым простым вариантом, и вам не нужно читать дальше.

Для всех подходов, отличных от AJAX, вам необходимо сохранить параметры запроса где-нибудь, включая шаблон Post / Redirect / Get. Этот шаблон заканчивается страницей, которая является результатом запроса GET, который пользователи могут обновить sh без указанного всплывающего окна. Что другие ответы довольно handwavy о, это как , чтобы правильно сделать это.

Варианты:

Сеанс сервера

При размещении на сервере вы можете позволить серверу сохранять параметры запроса в сеансе (все основные серверные инфраструктуры позволяют использовать сеансы), а затем перенаправить пользователя на общую страницу c /search-results, которая на серверная сторона считывает данные из сеанса и предоставляет пользователю результаты, полученные на основе запросов к базе данных, в сочетании с параметрами запроса из сеанса.

Недостатки:

  • Время сеансов обычно истекло И делают это по уважительным причинам. Если ваш пользователь нажимает F5, скажем, через 20 минут, его данные сеанса исчезают, как и параметры запроса.
  • Сессии распределяются между вкладками браузера. Если ваш пользователь ищет элемент A на вкладке 1 и элемент B на вкладке 2, параметры вкладки, которая была отправлена ​​последней, перезапишут более ранние вкладки при их обновлении.
  • Сессии для браузера. Как правило, нет простого способа поделиться сеансами (кроме помещения идентификатора сеанса в URL, но см. Первый маркер), поэтому вы не можете добавить в закладки или поделиться результатами поиска.

Локальное хранилище / куки

Вы можете подумать, что «куки могут содержать больше данных, чем строка запроса», но просто нет. Помимо наличия ограничения, они также разделяются между вкладками и не могут (легко) делиться между пользователями и не добавляются в закладки.

Локальное хранилище также не вариант, потому что пока оно может содержать гораздо больше данных - они не отправляются на сервер. Это локальное хранилище.

Серверное постоянное хранилище

Если ваши поисковые запросы на самом деле настолько сложны , что вам требуется несколько КБ параметров запроса, то вы возможно выиграет от сохранения параметров запроса в базе данных.

Таким образом, для каждого поискового запроса вы создаете новую запись базы данных search_query, которая содержит соответствующие параметры для запроса на выполнение, и, учитывая, что результаты поиска не являются частными, вы можете даже написать некоторый код, который ищет использовалась ли данная комбинация параметров ранее и сначала выполняется поиск.

Таким образом, вы получаете уникальный search_id, который указывает на набор параметров, с которыми вы можете выполнить запрос. Теперь вы можете перенаправить своих пользователей, чтобы они выполняли запрос GET на эту страницу:

/search-results?search_id=Xxx

И там вы отображаете результаты для данного запроса. Преимущества:

  • Вы можете кэшировать, добавить в закладки и поделиться URL-адресом /search-results?search_id=Xxx
  • Вы можете обновить sh страницу, отображающую результаты поиска без раздражающего всплывающего окна
  • Каждая вкладка браузера отображает свои собственные результаты поиска

Конечно, у этого подхода также есть недостатки:

  • Если вы не используете неугадываемый ключ для search_id, пользователи могут перечислять ранее поиск других пользователей
  • Каждый поиск требует постоянного серверного хранилища, если только вы не решите исключить более ранние поиски на основе некоторых критериев
1 голос
/ 03 февраля 2020

Эту проблему можно решить, применив шаблон Post / Redirect / Get .

Обычно вы получаете предупреждение браузера при попытке повторно отправить POST-запрос для обеспечения безопасности причины . Рассмотрим форму, где вы вводите личные данные для регистрации учетной записи или заказа продукта. Если вы дважды отправите свои данные, может случиться так, что вы зарегистрируетесь дважды или купите одну и ту же вещь два раза (конечно, это только теоретический пример). Таким образом, пользователь должен получить предупреждение при попытке отправить один и тот же запрос POST несколько раз. Это поведение предназначено и не может быть отключено, но его можно избежать, используя вышеупомянутый шаблон PRG.

Diagram of the double POST problem above being solved by PRG. Изображение из Википедии (опубликовано под LGPL ).

Простыми словами , этот шаблон можно использовать, чтобы избежать двойного представления данных формы, которые может привести к нежелательным результатам. Вы должны сконфигурировать свой сервер для перенаправления затронутых входящих POST-запросов, используя код состояния 303 («см. Другие») . Затем пользователь будет перенаправлен (используя запрос GET) на страницу подтверждения, показывающую, что запрос был успешным и теперь будет обработан. Если пользователь теперь перезагружает страницу, он / она будет перенаправлен на ту же страницу без повторной отправки запроса POST.

Однако эта стратегия может не всегда работать. Если сервер еще не получил первую отправку (например, из-за traffi c), если пользователь теперь повторно отправляет второй запрос POST, он все еще может быть отправлен.

Если вы предоставите дополнительную информацию о Ваш технический стек, я могу расширить свой ответ, добавив конкретные c примеры кода.

...