Когда перед вами стоит задача сделать редирект, есть соблазн не трогать сервер — написать пару строк JavaScript или добавить тег в HTML. Технически это работает. Практически — создаёт проблемы, о которых узнаёшь не сразу.
Этот материал о том, как именно работают клиентские редиректы, почему они проигрывают серверным почти по всем параметрам — и в каких конкретных ситуациях они всё-таки уместны.
Как работают клиентские редиректы
Серверный редирект — это ответ на первый же HTTP-запрос. Браузер спрашивает: «Что по этому адресу?», сервер отвечает: «Переходи вот сюда» — и всё, одно сетевое взаимодействие.
Клиентский редирект работает иначе:
- Браузер делает запрос к серверу
- Сервер возвращает 200 OK и отдаёт HTML-документ
- Браузер парсит HTML (или скачивает и исполняет JavaScript)
- Только теперь происходит переход на новый адрес
Пользователь видит либо мигание пустой страницы, либо часть старого контента — в зависимости от того, насколько быстро срабатывает редирект. Поисковый робот видит то же самое: страницу с кодом 200, которая потом куда-то ведёт.
JavaScript: window.location
Самый распространённый способ JavaScript-редиректа — присвоение нового адреса объекту window.location:
// Самый частый вариант
window.location.href = 'https://new-domain.ru';
// Без добавления в историю браузера
window.location.replace('https://new-domain.ru');
// Эквивалентно href
window.location.assign('https://new-domain.ru');
Разница между href, replace() и assign() ощутима только для пользователя: replace() не добавляет запись в историю, поэтому кнопка «Назад» не вернёт на старую страницу. Для поисковых роботов все три варианта идентичны.
Редирект можно поставить и в теге <script> прямо в <head> — тогда он сработает до рендеринга страницы, что чуть лучше для UX, но не меняет сути с точки зрения индексации.
Meta Refresh
Второй клиентский метод — HTML-тег в блоке <head>:
<!-- Мгновенный переход -->
<meta http-equiv="refresh" content="0; url=https://new-domain.ru">
<!-- Переход через 5 секунд -->
<meta http-equiv="refresh" content="5; url=https://new-domain.ru">
Этому тегу около 30 лет — он появился ещё в Netscape Navigator и задумывался для автоматического обновления страниц новостей. Потом его начали использовать для редиректов, и с тех пор он несёт репутационный шлейф: именно meta refresh активно использовали спамеры и фишинговые сайты в 2000-е.
Существует и HTTP-версия — заголовок Refresh: в ответе сервера. Результат тот же, но если вы уже управляете ответом сервера — проще сразу поставить 301.
Ключевое различие с точки зрения Google: задержка в параметре content меняет интерпретацию. При content="0" редирект считается постоянным (как 301). При любой задержке > 0 — временным (как 302). Это официальная позиция Google Search Central.
Как видят Google и Яндекс
Google: два прохода
Google обрабатывает JavaScript в два этапа:
Первый проход — краулинг. Googlebot скачивает URL, получает HTML-ответ, парсит ссылки. Если в ответе JavaScript — страница попадает в очередь на рендеринг.
Второй проход — рендеринг. Web Rendering Service запускает headless Chromium, исполняет JS и обрабатывает результат. Между первым и вторым проходом может пройти от нескольких секунд до нескольких дней.
Это означает: при JS-редиректе Google сначала видит страницу-источник (с кодом 200 и её контентом), а адрес назначения узнаёт только после рендеринга. Всё это время в индексе может находиться не тот URL, что вы хотите.
Важная деталь: Google использует актуальную версию Chromium («evergreen Googlebot»), поэтому современные JS-конструкции он понимает. Проблема не в совместимости — проблема в очереди рендеринга и задержке.
Яндекс: JS-рендеринг в бета
Яндекс поддерживает JS-рендеринг через функцию «Рендеринг страниц JavaScript» в Вебмастере — но она находится в бета-статусе и работает не для всех сайтов и не для всех страниц. По умолчанию Яндекс сканирует HTML-ответ и не исполняет JavaScript.
Практический вывод: сайт на чистом клиентском рендеринге (React или Vue без SSR) в Яндексе будет индексироваться значительно хуже, чем в Google. JS-редирект для Яндекса — это лотерея.
Производительность
Клиентский редирект всегда медленнее серверного. Разница ощутимая.
Серверный 301:
→ DNS lookup
→ TCP connect
→ HTTP запрос
← 301 Location: new-domain.ru ← всё, перенаправление здесь
→ DNS lookup (для нового домена)
→ TCP connect
→ HTTP запрос к новому URL
JS-редирект:
→ DNS lookup
→ TCP connect
→ HTTP запрос
← 200 OK + HTML + ссылка на script.js
→ скачать script.js
→ выполнить JS
→ window.location = new URL ← редирект только здесь
→ DNS lookup (для нового домена)
→ TCP connect
→ HTTP запрос к новому URL
Дополнительных шагов — три-четыре. При медленном соединении пользователь видит белый экран или мелькание старого контента. Core Web Vitals деградируют. Это не абстракция — это реальный пользовательский опыт, который Google учитывает в ранжировании.
Сравнительная таблица
| Метод | SEO-сигнал | Надёжность | Скорость | Передача веса |
|---|---|---|---|---|
| HTTP 301 / 308 | Постоянный ✓ | Максимальная | Мгновенно | Да |
| HTTP 302 / 307 | Временный ✓ | Максимальная | Мгновенно | Нет |
| Meta Refresh (0 сек) | Постоянный | Средняя | +1 RTT | Частично |
| Meta Refresh (>0 сек) | Временный | Средняя | Задержка | Нет |
| JavaScript redirect | Постоянный* | Низкая | +2–4 RTT | Непредсказуемо |
*Google может классифицировать как постоянный, но только после рендеринга.
Когда это всё-таки оправдано
Есть три ситуации, когда JS-редирект — это правильное решение, а не обходной манёвр:
1. После действия пользователя. Пользователь отправил форму, завершил оплату, вышел из системы. Сервер сделал своё дело, и теперь нужно перенаправить. Здесь window.location.replace() — абсолютно нормальный паттерн.
// После успешной оплаты
fetch('/api/checkout', { method: 'POST', body: data })
.then(res => res.json())
.then(data => {
window.location.replace(`/success?order=${data.orderId}`);
});
2. Страница с обратным отсчётом. «Вы будете перенаправлены через 5 секунд» — это UX-паттерн, а не SEO-решение. Пользователь должен видеть, что происходит.
let countdown = 5;
const timer = setInterval(() => {
document.getElementById('counter').textContent = --countdown;
if (countdown === 0) {
clearInterval(timer);
window.location.href = '/new-page';
}
}, 1000);
3. Клиентская маршрутизация в SPA. React Router, Vue Router, Next.js — все они используют History API для навигации внутри приложения. Это не редирект в классическом смысле, а часть архитектуры. Здесь JS — единственный правильный инструмент.
Мифы и заблуждения
«Google умеет рендерить JS — значит, JS-редирект работает нормально»
Умеет. Но в очереди. Между краулингом и рендерингом проходит время. Для быстро меняющихся страниц или при переезде домена эта задержка критична.
«Meta Refresh с нулевой задержкой — это то же самое, что 301»
Не совсем. Google интерпретирует его как постоянный редирект, да. Но Яндекс — менее предсказуемо. И это всё равно дополнительный HTTP-запрос. Если доступен серверный редирект — используйте его.
«JS-редирект передаёт ссылочный вес, раз Google его видит»
Google передаёт ссылочный вес с JS-редиректов, но только после рендеринга страницы. Если страница находится в очереди рендеринга несколько дней — всё это время вес не передаётся. При быстром переезде важного домена это потери.
«Это решение временное, потом переделаем нормально»
Классика. Временное становится постоянным. Если нет доступа к серверу сейчас — используйте DNS-сервис переадресации: он настраивается за 5 минут и работает правильно с первого дня.
«DNS-редирект сложнее настраивать и поддерживать»
Ровно наоборот. Люди, которые так думают, представляют себе ручную правку зональных файлов на VPS в три часа ночи. Реальность с современными сервисами переадресации: вы указываете источник, назначение, тип — и больше ничего не делаете. Никогда. SSL-сертификат выпускается автоматически и продлевается сам. Нет сервера, за которым нужно следить. Нет файлов, которые нужно деплоить. Нет обновлений, которые нужно применять. Если нужно поменять адрес назначения — один клик в интерфейсе, изменение вступает в силу сразу. JS-редирект при том же сценарии требует: открыть редактор, поправить код, собрать проект, залить на хостинг, проверить. Это не «сложнее» и «проще» — это принципиально разные уровни операционной нагрузки.
Что использовать вместо
Для большинства задач — серверный редирект. Если доступа к серверу нет, варианты в порядке убывания надёжности:
-
DNS-сервис переадресации — принимает домен на свои серверы, автоматически выдаёт SSL и настраивает правильный 301. Хостинг не нужен вообще: никаких файлов, никакого сервера, никакого кода. Редирект настраивается через интерфейс и работает на уровне DNS — домен просто указывает на сервис, который всё делает сам.
-
Серверный скрипт — если контролируете хостинг, но не конфиг сервера: PHP
header('Location: ...')или аналог на вашем бэкенде. Правильный HTTP-статус, никакого JS. Но для этого нужен работающий хостинг с файлами на нём. -
Meta Refresh (0 сек) — только если два предыдущих варианта недоступны и нужен быстрый временный фикс. Тоже требует загрузки HTML-файла куда-то.
-
JavaScript — только для трёх случаев, описанных выше.
Обратите внимание на контраст: JS-редирект и meta refresh требуют, чтобы где-то лежал файл — а значит, нужен хостинг, деплой, поддержка. DNS-сервис переадресации работает без всего этого. Если задача — просто перенаправить домен, нет смысла поднимать инфраструктуру ради одной строки кода.
Если ситуация не подходит ни под один из трёх оправданных случаев — это не аргумент в пользу JS-редиректа. Это аргумент в пользу того, чтобы получить нормальный доступ.