Какое правильное поведение ожидается от перенаправления HTTP POST = ›302 на GET?

Какое правильное поведение ожидается от перенаправления POST => 302 на GET?

В Chrome (и, вероятно, в большинстве браузеров), после того, как я отправляю POST (на ресурс, который хочет, чтобы я перенаправил) и получаю перенаправление 302, браузер автоматически выдает GET в местоположении 302. Это даже хорошо известный шаблон. Но, как я прочитал спецификацию, кажется, что этого не должно происходить.

Согласно спецификации HTTP

Если код состояния 302 получен в ответ на запрос, отличный от GET или HEAD, пользовательский агент НЕ ДОЛЖЕН автоматически перенаправлять запрос , если он не может быть подтвержден пользователем, поскольку это может изменить условия, при которых был отправлен запрос.

И скрипач показывает:

REQUEST 1: POST URLA
RESPONSE 1: 302 redirect to URLB
REQUEST 2: GET URLB

В приведенном выше разделе, кажется, говорится, что браузер не должен делать запрос GET? Что мне не хватает?

  1. Что-то ранее в спецификации, что делает этот раздел неуместным
  2. Я неправильно понимаю автоматическое перенаправление (и браузер Chrome, который выполнял GET, на самом деле не перенаправлял автоматически)
  3. Мое понимание подтвердило это как пользователь
  4. Что-то другое?

person Joshua Ball    schedule 12.07.2013    source источник


Ответы (3)


Сама следующая строка в спецификации начинается:

Примечание. RFC 1945 и RFC 2068 указывают, что клиенту не разрешено изменять метод перенаправленного запроса. Однако большинство существующих реализаций пользовательского агента обрабатывают 302, как если бы это был ответ 303, выполняя GET для значения поля Location независимо от исходного метода запроса. Коды состояния 303 и 307 были добавлены для серверов, которые хотят однозначно указать, какой тип реакции ожидается от клиента.

И сразу после этого объясняется, как следует обращаться с 303, и это именно то, что вы видите.


Если вы спрашиваете, почему серверы все еще используют 302 вместо 307, которые все текущие браузеры будут обрабатывать правильно, это потому, что старые браузеры не справятся с этим. Если вам интересно, почему браузеры обрабатывают 302 как 303, это потому, что старые серверы ожидают этого. На самом деле выхода из этого цикла нет, и, вероятно, для HTTP было бы лучше просто вернуть 302, чтобы оно означало то, что он имел обыкновение означать, и отказаться от него (для не-GET / HEAD) в пользу 307.

person abarnert    schedule 12.07.2013
comment
abarnet: поясните, пожалуйста, что вы имеете в виду под старыми браузерами. - person Julian Reschke; 12.07.2013
comment
@JulianReschke: Я точно не знаю. Если бы мне пришлось угадывать, я бы предположил, что урожай около IE6 и FF 1.9. Но помните, что настольные браузеры (и мобильные браузеры WebKit) - не единственные пользовательские агенты; есть множество людей, использующих другие устройства с установленными браузерами, вручную написанными клиентами веб-сервисов или инструментами для очистки и т. д. - person abarnert; 12.07.2013
comment
@JulianReschke: Кроме того, я должен был упомянуть, что 303 и 307 находятся только в HTTP / 1.1. Существует множество серверов и кешей (и некоторых пользовательских агентов), которые либо не могут обрабатывать 1.1, либо отключают его. Между тем я только что нашел сообщение в блоге от команды IE, которое выглядит актуальным. - person abarnert; 12.07.2013
comment
FF 1.9 мне кажется неактуальным. IE6 действительно поддерживает 307. В конце дня вы всегда найдете какой-нибудь клиент, который сломан, поэтому вам нужно провести черту. - person Julian Reschke; 12.07.2013
comment
@JulianReschke: Я не говорю, что ваш сервер должен злоупотреблять 302, я объясняю, почему многие серверы до сих пор это делают. Пока все новые браузеры правильно обрабатывают нарушенное поведение (а они это делают) и есть старые браузеры, требующие нарушенного поведения, серверы будут продолжать злоупотреблять им. Это нехорошо, но факт. - person abarnert; 12.07.2013

abarnert был прав! У меня была такая же проблема с Google App Engine, но я нашел другое решение.

Моя проблема с appengine заключалась в том, что я сделал POST с формой для GO formHandler на бэкэнде. Но это было выполнено следующим образом.

запрос 1: GET / formHandler -> ответ 1: 302 Найдено

запрос 1: POST / formHandler -> ответ 1: 302 Найдено

запрос 1: GET / formHandler -> ответ 1: 200 Хорошо.

Дополнительно я получил

На запрошенном ресурсе отсутствует заголовок Access-Control-Allow-Origin.

Это была проблема CORS.

Однако решение заключается в использовании HTTP S вместо HTTP.

Тогда у вас будет

запрос: POST / formHandler -> ответ: 200 Хорошо

person Kalpa Gunarathna    schedule 21.12.2016

Вы можете прочитать http://greenbytes.de/tech/webdav/draft-ietf-httpbis-p2-semantics-22.html#rfc.section.6.4.p.3, который пытается прояснить ситуацию.

Примечание. В HTTP / 1.0 коды состояния 301 (перемещено постоянно) и 302 (найдено) были определены для первого типа перенаправления ([RFC1945], раздел 9.3). Ранние пользовательские агенты разделяются по тому, будет ли метод, примененный к цели перенаправления, таким же, как исходный запрос, или будет переписан как GET. Хотя HTTP изначально определил первую семантику для 301 и 302 (чтобы соответствовать ее исходной реализации в CERN) и определил 303 (см. Другое), чтобы соответствовать последней семантике, преобладающая практика постепенно сошлась на последней семантике также и для 301 и 302. Первая версия HTTP / 1.1 добавила 307 (временное перенаправление), чтобы указать на прежнюю семантику, не подвергаясь влиянию различных практик. Спустя более 10 лет большинство пользовательских агентов все еще переписывают методы для 301 и 302; следовательно, эта спецификация делает это поведение совместимым, когда исходным запросом является POST.

person Julian Reschke    schedule 12.07.2013