Браузеры делают GET, получив 302 в ответ на POST

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

Этому поведению десятки лет. В спецификации HTTP/1.0 есть заметка:

Note: When automatically redirecting a POST request after receiving a 302 status code, some existing user agents will erroneously change it into a GET request.

Насколько я понимаю, последующие браузеры сохранили это ошибочное с точки зрения разработчиков спецификации поведение. В итоге, чтобы как-то это разрулить, в HTTP/1.1 ввели два статуса — 303 и 307.

Первый предполагал именно это поведение, которое браузеры выбрали как правильное:

The response to the request can be found under a different URI and SHOULD be retrieved using a GET method on that resource.

Второй же предполагал альтернативное поведение — сохранять метод при перенаправлении.

А поскольку с кодом 301 были те же самые проблемы (браузеры превращали POST в GET), современный стандарт, описывающий семантики HTTP вводит ещё один код — 308.

Итого, если суммировать:

  • Браузеры превратят POST в GET при получении 301 или 302 от сервера. Если важно сохранить POST и не важна поддержка старых HTTP-клиентов, то следует использовать 308 и 307 соответственно.
  • 303 стоит использовать только если хочется явного превращения перенаправления в GET. Например, если браузер посылает POST с формой заказа, и надо показать ему страницу о том, что заказ успешен.

С PUT, кажется, та же шляпа.