Редиректы
Редирект — способ сказать клиенту: «этого больше здесь нет, иди туда». HTTP имеет несколько кодов, отличающихся в двух измерениях: постоянный/временный и сохраняет ли метод.
Матрица редиректов
| Код | Название | Постоянный | Сохраняет метод | Когда использовать |
|---|---|---|---|---|
| 301 | Moved Permanently | Да | Исторически нет (POST→GET), но противоречиво | Смена URL сайта навсегда |
| 302 | Found | Нет | Исторически нет | Legacy, часто заменяется на 303 или 307 |
| 303 | See Other | Нет | Всегда меняет на GET | После POST → GET (PRG pattern) |
| 307 | Temporary Redirect | Нет | Да, всегда сохраняет | Временный редирект с POST/PUT/DELETE |
| 308 | Permanent Redirect | Да | Да, всегда сохраняет | Постоянный редирект современных API |
Историческая путаница 301/302
По RFC 7231 формально 301/302 не должны менять метод. Но браузеры массово это делали ещё с Netscape — POST превращали в GET. Чтобы разрешить путаницу, ввели новые коды:
- 303 — гарантированно превращает в GET.
- 307/308 — гарантированно сохраняет метод.
Для новых сервисов используй 303/307/308 — их поведение чётко определено.
Пример 301
HTTP/1.1 301 Moved Permanently
Location: https://new.example.com/page
Cache-Control: max-age=31536000
Браузер запомнит редирект надолго. Осторожно с 301 — если ошибся, откатить сложно (клиент не будет спрашивать снова).
PRG pattern (Post/Redirect/Get)
Классический паттерн для веб-форм:
- User сабмитит форму —
POST /submit. - Сервер обрабатывает, отвечает
303 See Other, Location: /success. - Браузер идёт
GET /success. - User видит success-страницу.
Плюс: нажатие F5 не делает повторный POST (не будет «отправить форму ещё раз?»).
Meta refresh
<meta http-equiv="refresh" content="5; url=/new-page">
HTML-редирект через 5 секунд. Устарело, плохо для SEO, но иногда используется для «спасибо, вас перенаправляем...» страниц.
JS-редирект
window.location.href = '/new-page';
window.location.replace('/new-page'); // без записи в history
Работает всегда, но требует JS. Не индексируется поисковиками так же хорошо как 301.
Циклические редиректы
/a → /b → /a — цикл. Браузеры детектят и показывают ERR_TOO_MANY_REDIRECTS обычно после 20 переходов.
Nginx имеет отдельную защиту: internal redirect ограничен 10 хопами (server_names_hash_bucket_size).
SEO и редиректы
| Как понимает Google | |
|---|---|
| 301 | Полностью переносит ссылочный вес на новый URL |
| 302 | Раньше почти не переносил, с 2016 — тоже полностью |
| 307/308 | Аналогично 302/301 |
| meta refresh с 0 сек | Как 301 |
| meta refresh с задержкой | Игнорируется |
| JS-редирект | Понимается, но медленно |
Тонкости
- Location может быть относительным.
Location: /new— работает. Абсолютные надёжнее. - 301 кэшируется агрессивно. Если ошибся — переопределяй через
Cache-Control: max-age=0, must-revalidate. - HTTP → HTTPS. Стандартно 301. Плюс HSTS-заголовок чтобы браузер запомнил.
- Trailing slash.
/foo→/foo/— обычно 301. - www vs no-www. Выбираешь одно, редиректишь другое через 301.
Настройка
# nginx
server {
listen 80;
server_name example.com;
return 301 https://$server_name$request_uri;
}
# Apache .htaccess
Redirect 301 /old-page /new-page
RewriteRule ^old/(.*)$ /new/$1 [R=301,L]
# Express.js
res.redirect(301, '/new-page');
res.redirect(303, '/success');