303 See Other: переспрямування після POST форми
303 See Other повідомляє клієнту, що запит оброблено, а результат знаходиться за іншою адресою, яку слід отримати методом GET. Це правильна відповідь на відправлення форми, після якої відвідувач має опинитися на сторінці результату чи підтвердження, а не залишатися на POST-запиті.
Навіщо потрібен 303
303 насправді не про перенесення ресурсу. Він про відокремлення дії від її результату. Клієнт надсилає POST, сервер виконує дію, а потім, замість того щоб повернути результат прямо у відповіді на POST, відповідає кодом 303 із заголовком Location. Клієнт робить новий GET-запит за цією адресою, і в адресному рядку браузера з'являється звичайний 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 на нову адресу, що для відправлення форми означає виконання дії двічі.
Одне практичне застереження: 303 з'явився в HTTP/1.1, тож клієнт, що говорить на HTTP/1.0, може його не зрозуміти. Деякі фреймворки саме тому за замовчуванням використовують 302. У сучасному вебі це рідко стає реальним обмеженням, але саме цим пояснюється різниця в поведінці за замовчуванням між мовами.
Де ще трапляється 303
- API, що запускають довгу роботу. POST запускає задачу і відповідає 303 з URL статусу цієї задачі, або 202 з URL статусу в тілі відповіді. Використовують обидва підходи; перевага 303 в тому, що браузер переходить за ним автоматично.
- Потоки OAuth і входу в систему. Деякі сервери авторизації перенаправляють назад у клієнтський застосунок кодом 303, щоб зворотний виклик запитувався методом GET незалежно від того, як прийшов початковий запит.
- Налаштування пов'язаних даних і узгодження вмісту, що розрізняють реальний об'єкт і документ, який його описує, і використовують 303, щоб направити клієнтів від ідентифікатора до документа.
Як застосовувати і перевіряти
- Після успішного POST повертайте 303 з абсолютним
Location, що вказує на сторінку результату. Не рендеріть результат прямо у відповіді. - Зробіть адресу призначення ідемпотентною. Її буде запитано знову при кожному перезавантаженні й кожному переході назад, тож отримувати її методом GET повторно має бути безпечно.
- Будь-яке одноразове повідомлення, наприклад "зміни збережено", зберігайте в стані сесії чи параметрі запиту, а не в тілі переспрямування. Тіло відповіді 303 зазвичай не відображається.
- Перевірте код і адресу призначення:
Ви маєте побачитиcurl -si -X POST -d "name=test" https://example.com/submit | grep -Ei "^(HTTP|location)"HTTP/1.1 303 See Otherі URL результату. - Перейдіть за ним і переконайтеся, що другий запит - це GET, який повертає 200. Якщо в логах сервера видно повторний POST, значить діє правило 307, і його потрібно змінити.
- Перевірте, що адреса призначення сама не є переспрямуванням. 303, що веде на 301, а той - на справжню сторінку, це три переходи заради одного відправлення форми.
Моніторинг ендпоінтів за формою
Зламаний потік post-потім-переспрямування непомітний для перевірки, яка звертається лише до головної сторінки. Сайт працює, форма відображається, і лише ті, хто її надсилає, натрапляють на збій. Ловіть це заздалегідь, спостерігаючи за ендпоінтами за дією - сторінкою результату, URL підтвердження і маршрутом статусу задачі - і перевіряючи очікуваний код стану та вміст для кожного з них. HostTracker пропонує 13 типів моніторів і сповіщає електронною поштою, SMS, голосовим дзвінком, у Slack, Telegram та іншими способами. Перевірте, що повертає будь-який URL, за допомогою інструмента HTTP-перевірки, а про сусідні коди читайте в 301 проти 302 і в повному посібнику про родину переспрямувань 3xx.