Почему HTTP не имеет перенаправления POST?

162

HTTP-перенаправления выполняются с помощью HTTP-кодов 301 и 302 (возможно, также других кодов) и поля заголовка, известного как «Location», в котором есть адрес нового места для перехода. Однако браузеры всегда отправляют запрос «GET» на этот URL.

Однако часто вам нужно перенаправить пользователя в другой домен через POST (например, банковские платежи). Это общий сценарий и действительно требование. Кто-нибудь знает, почему такое стандартное требование игнорируется в спецификации HTTP? Обходной путь - отправить форму (с параметрами в скрытых полях) с установленным действием в целевое местоположение (значение поля заголовка Location ) и использовать его setTimeoutдля отправки формы в целевое местоположение.

Саид Нямати
источник
1
Код статуса 307 - это то, что вы ищете? Смотрите мой ответ ниже.
Дэвид Руттка

Ответы:

180

В HTTP 1.1 фактически существует код состояния ( 307 ), который указывает, что запрос должен повторяться с использованием того же метода и отправки данных .

Как уже говорили другие, здесь есть вероятность неправильного использования, поэтому многие фреймворки придерживаются 301 и 302 в своих абстракциях. Однако при правильном понимании и ответственном использовании вы сможете выполнить то, что ищете.

Обратите внимание, что в соответствии со спецификацией W3.org , когда METHODнет HEADили GET, пользовательские агенты должны запросить пользователя перед повторным выполнением запроса в новом месте. Вы также должны предоставить пользователю примечание и резервный механизм на случай, если старые агенты пользователя не уверены, что делать с 307.

Используя эту форму:

<form action="Test307.aspx" method="post">
    <input type="hidden" name="test" value="the test" />
    <input type="submit" value="test" />    
</form>

И если Test307.aspx просто вернет 307 с адресом Location: http://google.com , Chrome 13 и Fiddler подтвердят, что «test = the test» действительно опубликован в Google. Конечно, дальнейший ответ - 405, поскольку Google не позволяет POST, но он показывает механику.

Для получения дополнительной информации см. Список кодов состояния HTTP и спецификацию W3.org .

307 Временное перенаправление (начиная с HTTP / 1.1). В этом случае запрос должен повторяться с другим URI, но в будущих запросах все еще может использоваться исходный URI. 2 В отличие от 303, метод запроса не должен изменяться при повторном выдаче исходного запроса. Например, запрос POST должен повторяться с использованием другого запроса POST.

Дэвид Руттка
источник
2
@DavidRuttka, какая поддержка браузера в дикой природе ?
Пейсер
5
@DavidRuttka, возможно, вы захотите обновить свой ответ, чтобы учесть rfc7231 (устарели rfc2616). Запрос пользователя основан на требовании в rfc2616. Это требование удалено в rfc7231, а rfc7231 также вводит требование, чтобы перенаправления 307 не изменяли метод запроса (который вы упоминаете в своей цитате в конце вашего ответа).
Нибариус
Обратите внимание, что в соответствии с tools.ietf.org/id/draft-hunt-http-rest-redirect-00.html «Коды перенаправления HTTP 301-306 НЕ ДОЛЖНЫ использоваться, если поставщик услуг не знает, что клиент на самом деле является пользователем. «Похоже, службы ReSTful должны использовать 308 вместо 301. Однако это только черновик.
Брюс Адамс
49

Я нашел хорошее объяснение на этой странице здесь .

Простейшие ситуации на WWW - это «идемпотентные» транзакции, то есть те, которые можно повторять, не причиняя никакого вреда. Обычно это транзакции «GET», либо потому, что они извлекают прямые ссылки на URL (например, атрибуты href = или src = в HTML), либо потому, что они представляют собой отправку формы с использованием метода GET. Перенаправление транзакции такого типа является простым и не вызывает вопросов: клиент получает ответ о перенаправлении, включая заголовок Location:, который указывает новый URL-адрес, и клиент реагирует на него, повторно выполняя транзакцию для нового URL-адреса. Существует разница между различными 30-кратными кодами состояния, связанными с этими перенаправлениями, в их подразумеваемой кешируемости, но в остальном они в основном схожи (301 и 302) в ответ на запросы GET.

Транзакции POST различаются, поскольку они в принципе определены как неидемпотентные (например, заказ пиццы, голосование и т. Д.) И не должны произвольно повторяться.

Спецификации протокола HTTP разработаны с учетом этого различия: метод GET определен как изначально идемпотентный, тогда как метод POST определен, по крайней мере, потенциально неидемпотентным; Спецификации требуют ряда мер предосторожности, которые должны быть приняты клиентскими агентами (такими как браузеры) для защиты пользователей от непреднамеренной (повторной) отправки транзакции POST, которую они не планировали, или отправки POST в контекст, который они не хотели бы ,

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

сокол
источник
большая часть рассуждений относится к тем дням, когда промежутки были медленными и ненадежными (что они все еще есть во многих местах мира). Я отчетливо помню, когда пользовался набором номера, и был случайно отключен всякий раз, когда кто-то поднимал трубку. Было бы лучше перезагрузить страницу и посмотреть, в каком состоянии находился сервер, чем повторно отправлять информацию и рисковать выполнить одно и то же действие дважды.
zzzzBov
@Falcon, будет ли увеличение "счетчика посетителей" считаться неидемпотентным? Если так, то почти ни один веб-сайт в наши дни не делает идемпотентных GET ...
Pacerier
@Pacerier: обычно идемпотент интерпретируется как «идемпотент осмысленным образом», например, покупая один и тот же предмет дважды, а не совершая два посещения. В противном случае вы были бы совершенно правы. Но на самом деле спецификация должна требовать, чтобы серверы были значимо идемпотентными, когда это необходимо, например, для вставки идентификатора на страницу, чтобы избежать дублирования - не требуя, чтобы браузер задавал пользователю вопрос, на который у него нет возможности ответить с какой-либо точностью. Независимо от этого, предотвращение перенаправления POST не влияет на идемпотентность; это просто сообщение о том, что цель запроса на самом деле там.
Лоуренс Дол
Я не понимаю, как это имеет смысл для этих рассуждений. Скажем, я на веб-сайте банка Chase и отправляю форму. Я уже согласился / доверял им. Так что, если они должны перенаправить эти данные на другую страницу, зачем мне снова соглашаться. Или другой пример: скажем, я человек, который отключает JavaScript по умолчанию. Однажды я заполняю онлайн заявку на ипотеку, и когда я отправляю форму, появляются ошибки. Было бы здорово, если бы приложение могло перенаправлять (с помощью POST) на страницу, которую я только что заполнил, для предварительного заполнения данных.
b01
@Flacon, мне нужны доказательства того, что ограничение перенаправления с помощью POST может предотвратить хаос в любом случае. Так как я сначала должен доверить приложению свои данные, они могут делать с ним все, что захотят, как только получат данные. И я не думаю, что перенаправления более уязвимы, чем запрос с POST.
b01
3

GET (и несколько других методов) определены как «SAFE» в спецификации http ( RFC 2616 ):

9.1.1 Безопасные методы

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

В частности, было установлено, что методы GET и HEAD НЕ ДОЛЖНЫ иметь значение выполнения действия, отличного от извлечения. Эти методы следует считать «безопасными». Это позволяет пользовательским агентам представлять другие методы, такие как POST, PUT и DELETE, особым образом, чтобы пользователь знал о том, что запрашивается небезопасное действие.

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

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

Хотя это изменилось в JavaScript, традиционно существовали разные пользовательские интерфейсы - пользователи могли инициировать GET-запросы, щелкая ссылки, но для заполнения POST-запроса приходилось заполнять форму. Я думаю, что разработчики HTTP стремились поддерживать различие между безопасными и небезопасными методами.

Я также не думаю, что когда-либо нужно будет перенаправлять на POST. Любое действие, которое необходимо выполнить, можно предположительно выполнить, вызвав функцию в коде на стороне сервера, или, если это должно произойти на другом сервере, вместо того, чтобы отправлять перенаправление, содержащее URL-адрес браузера для POST, на сервер. может сделать запрос к самому серверу, действуя как прокси для пользователя.

bdsl
источник