Перейти к основному содержимому

Руководства / Коды состояния HTTP: разбор

303 See Other: редирект после POST-отправки формы

303 See Other сообщает клиенту, что запрос обработан, а результат находится по другому URL, который следует запросить методом GET. Это правильный ответ на отправку формы, после которой посетитель должен оказаться на странице результата или подтверждения, а не оставаться на POST.

Для чего нужен 303

303 на самом деле не про перенос ресурса. Он про отделение действия от его результата. Клиент отправляет POST, сервер выполняет действие, а затем вместо того чтобы вернуть результат прямо в ответе на POST, отвечает кодом 303 с заголовком Location. Клиент делает новый GET по этому адресу, и в адресной строке браузера оказывается обычный URL, который можно добавить в закладки и перезагрузить.

Определяющее правило - метод: каким бы ни был исходный метод запроса, повторный запрос к URL из Location всегда GET. Это прямая противоположность 307 и 308, которые требуют сохранения исходного метода и тела запроса.

Post/Redirect/Get и какую проблему он решает

Без редиректа после POST страница результата принадлежит самому POST-запросу, что вызывает знакомые проблемы:

  • Нажатие "обновить" повторно отправляет форму, поэтому заказ оформляется или комментарий публикуется дважды. Браузеры предупреждают об этом диалогом "подтвердите повторную отправку формы", что само по себе неприятный опыт.
  • Страницу нельзя добавить в закладки или поделиться ею, потому что URL не описывает содержимое.
  • Кнопка "назад" приводит к запросу на повторную отправку вместо предыдущей страницы.

Post/Redirect/Get решает все эти проблемы разом. POST выполняет действие и отвечает 303; браузер делает GET на URL результата; повторная загрузка теперь просто заново получает безобидную страницу. Именно поэтому почти в каждом фреймворке есть хелпер "редирект после сохранения".

303 против 302 против 307

  • 302 Found - временный редирект, чья обработка метода исторически неоднозначна. Большинство клиентов при следовании ему превращают POST в GET, что обычно и нужно, но стандарт этого не требует. Многие фреймворки до сих пор отдают 302 для схемы post-затем-редирект, и на практике это работает.
  • 303 See Other делает это поведение явным и обязательным. Если ваше намерение - "не повторяй мой POST, вместо этого сделай GET сюда", 303 выражает это однозначно.
  • 307 Temporary Redirect - как раз тот код, которого здесь стоит избегать. Он требует повторить POST на новый URL, что для отправки формы означает выполнение действия дважды.

Одна практическая оговорка: 303 появился в HTTP/1.1, поэтому клиент, говорящий на HTTP/1.0, может его не понять. Некоторые фреймворки по этой причине по умолчанию используют 302. В современном вебе это редко становится реальным ограничением, но именно этим объясняется разница в поведении по умолчанию между языками.

Где еще встречается 303

  • API, запускающие долгую работу. POST запускает задачу и отвечает 303 с URL статуса этой задачи, либо 202 с URL статуса в теле ответа. Используются оба паттерна; у 303 есть преимущество в том, что браузер следует по нему автоматически.
  • Потоки OAuth и входа в систему. Некоторые серверы авторизации перенаправляют обратно в клиентское приложение кодом 303, чтобы колбэк запрашивался методом GET независимо от того, как пришел исходный запрос.
  • Настройки связанных данных и согласования содержимого, различающие реальный объект от документа, его описывающего, и использующие 303, чтобы направить клиентов от идентификатора к документу.

Как использовать и проверить

  1. После успешного POST возвращайте 303 с абсолютным Location, указывающим на страницу результата. Не отдавайте результат прямо в теле ответа.
  2. Сделайте адрес назначения идемпотентным. Он будет запрашиваться заново при каждой перезагрузке и каждом переходе назад, поэтому его должно быть безопасно получать повторно методом GET.
  3. Любое одноразовое сообщение, например "изменения сохранены", храните в состоянии сессии или параметре запроса, а не в теле редиректа. Тело ответа 303 обычно не отображается.
  4. Проверьте код и адрес назначения:
    curl -si -X POST -d "name=test" https://example.com/submit | grep -Ei "^(HTTP|location)"
    Вы должны увидеть HTTP/1.1 303 See Other и URL результата.
  5. Перейдите по нему и убедитесь, что второй запрос - это GET, возвращающий 200. Если в логах сервера виден повторный POST, значит используется правило 307, и его нужно менять.
  6. Проверьте, что адрес назначения сам не является редиректом. 303, ведущий в 301, а тот - на настоящую страницу, это три перехода ради одной отправки формы.

Мониторинг эндпоинтов за формой

Сломанный поток post-затем-редирект невидим для проверки, которая обращается только к главной странице. Сайт работает, форма отображается, и только те, кто ее отправляет, натыкаются на сбой. Ловите это заранее, наблюдая за эндпоинтами за действием - страницей результата, URL подтверждения и маршрутом статуса задачи, - и проверяя ожидаемый код состояния и содержимое для каждого из них. HostTracker предлагает 13 типов мониторов и оповещает по email, SMS, голосовым звонком, в Slack, Telegram и другими способами. Проверьте, что возвращает любой URL, с помощью инструмента HTTP-проверки, а о соседних кодах читайте в 301 против 302 и в полном руководстве по семейству перенаправлений 3xx.

Проверить сейчас

Запустите бесплатную проверку своего сайта - аккаунт не нужен.

HTTP check

Следить за этим постоянно

Получайте оповещение в момент сбоя: HostTracker проверяет более чем из 300 локаций и уведомляет по email, SMS, в Slack, Telegram и не только.

Возможности HostTracker

Ещё в этом разделе: Коды состояния HTTP: разбор