Браузеры делают 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, кажется, та же шляпа.