React Router и SEO: правильные URL, ссылки, 404 и canonical

    React Router позволяет строить навигацию между представлениями React-приложения без полной перезагрузки страницы, но сам по себе не делает маршруты доступными.

    Виктор С.·5 сентября 2026 г.·12 мин чтенияSEO
    Виктор Сорокин — технический директор и основатель Like SitesАвтор статьиВиктор С.Технический директор · Основатель Like Sites

    React Router и SEO: правильные URL, ссылки, 404 и canonical

    React Router позволяет строить навигацию между представлениями React-приложения без полной перезагрузки страницы, но сам по себе не делает маршруты доступными для поисковых систем. Для SEO важны обычные URL, которые сервер обрабатывает с корректными HTTP-кодами, ссылки с атрибутом href, доступный исходный HTML, отсутствие soft 404 и согласованный canonical. Если маршрутизация существует только внутри JavaScript, а сервер для любого адреса возвращает одну и ту же страницу со статусом 200, поисковая система может не различить реальные страницы, ошибки и дубли.

    Что решает React Router

    React Router связывает адрес браузера с компонентом, который должен быть показан пользователю. При переходе внутри приложения маршрутизатор может изменить URL через History API и заменить содержимое без полной загрузки документа. Это удобно для интерфейсов, где пользователь долго работает внутри приложения: каталогов, личных кабинетов, фильтров и многошаговых форм.

    Для публичного сайта услуг одного клиентского маршрутизатора недостаточно. Поисковый робот должен обнаружить URL, получить по нему понятный ответ сервера и увидеть содержание страницы. Google описывает обработку JavaScript-приложений как последовательность обхода, рендеринга и индексации: сначала робот запрашивает URL и читает HTML, затем при доступных ресурсах выполняет JavaScript, повторно извлекает ссылки из отрендерированного HTML и использует результат для индексации. Серверный или предварительный рендеринг остаётся полезным, потому что ускоряет получение содержания и не требует от каждого робота полного выполнения JavaScript.

    Поэтому React Router следует рассматривать как часть маршрутизации приложения, а не как замену серверной конфигурации. SEO-результат определяется всей цепочкой: ссылка, URL, ответ сервера, HTML, JavaScript, метаданные, canonical и обработка ошибок.

    Каким должен быть SEO-URL

    Индексируемый URL должен быть постоянным, понятным и однозначно связанным с одной страницей. Для страницы услуги обычно подходит путь вроде /services/web-development, а для статьи — /blog/react-router-seo. Важен не конкретный формат, а стабильность адреса, предсказуемость маршрута и отсутствие нескольких равнозначных вариантов без необходимости.

    Для публичных страниц стоит заранее определить правила:

    • используется один протокол и основной домен;
    • trailing slash применяется одинаково на всём сайте;
    • регистр букв не создаёт разные версии одной страницы;
    • параметры добавляются только тогда, когда меняют содержание или необходимы приложению;
    • идентификаторы и технические значения не заменяют смысловой slug там, где URL предназначен для пользователей;
    • старые адреса перенаправляются на новые, если страница действительно перемещена;
    • несуществующие адреса возвращают 404 или 410, а не копию главной страницы.

    URL с фрагментом после символа решётки не является полноценной заменой отдельному адресу для контента. Google прямо указывает, что ссылки с href, содержащие обычные пути, помогают обнаруживать URL, тогда как фрагменты не являются надёжным способом загрузки разных представлений. Для маршрутов React-приложения следует использовать History API и адреса вида /services, /services/design или /blog/article-name.

    Ссылки и History API

    Поисковая система обнаруживает навигацию прежде всего через элементы ссылки с атрибутом href. Кнопка, которая вызывает обработчик и программно меняет состояние приложения, может быть удобной частью интерфейса, но не заменяет обычную ссылку на публичную страницу.

    В React навигация должна сохранять понятное поведение ссылки. Пользователь должен иметь возможность открыть адрес в новой вкладке, скопировать его, перейти по нему с отключённым JavaScript и вернуться назад средствами браузера. Обработчик клика может ускорять переход внутри приложения, но он не должен удалять смысл обычного href.

    History API позволяет изменять адрес без полной перезагрузки документа и сохранять историю переходов браузера. При этом изменение URL на клиенте не создаёт страницу на сервере автоматически. Если пользователь напрямую откроет /blog/react-router-seo, сервер должен знать, какой документ вернуть для этого адреса. Для статически собранного сайта сервер обычно отдаёт заранее подготовленный HTML-файл. Для серверного рендеринга сервер формирует ответ по маршруту. Для закрытых разделов запрос может требовать авторизацию.

    Основная ошибка возникает, когда приложение корректно работает после перехода с главной страницы, но прямой запрос к вложенному URL возвращает ошибку сервера или HTML главной страницы. Такой сайт может выглядеть исправным при обычной навигации, но иметь проблемы с обходом, закладками, внешними ссылками и индексацией.

    Серверная обработка маршрутов

    Маршруты React и маршруты веб-сервера должны описывать одну и ту же структуру адресов. Для каждого публичного пути нужно определить, какой документ выдаётся, какие данные загружаются и какой статус возвращается.

    Для статических страниц сервер может настроить fallback на HTML приложения, но универсальный fallback нельзя применять без проверки существования маршрута. Если любой неизвестный адрес получает главную страницу со статусом 200, возникает soft 404. Внешне пользователь видит страницу, однако сервер сообщает, что ресурс найден. Поисковая система должна сама определить, что содержание не соответствует запрошенному адресу, и такая диагностика может быть неполной.

    Корректный вариант зависит от архитектуры:

    • существующий статический маршрут возвращает собственный HTML со статусом 200;
    • существующая серверная страница возвращает данные и HTML со статусом 200;
    • перемещённый URL возвращает постоянное перенаправление на новый адрес;
    • отсутствующий ресурс возвращает 404;
    • окончательно удалённый ресурс, для которого нет замены, может возвращать 410;
    • закрытый раздел возвращает ответ, соответствующий требованиям авторизации, а не публичную копию страницы.

    Google рекомендует использовать осмысленные HTTP-коды. Для single-page application, где клиентский маршрутизатор затрудняет выдачу настоящего 404, Google допускает переход к URL, который сервер обрабатывает как 404, либо добавление noindex на страницу ошибки. Серверный статус остаётся предпочтительным, потому что он точно сообщает роботам состояние ресурса.

    Почему возникает soft 404

    Soft 404 — это ситуация, когда страница выглядит как ошибка или не содержит запрошенного ресурса, но сервер возвращает 200. В React-приложениях это часто происходит по одному из сценариев:

    • неизвестный slug передаётся в один универсальный компонент;
    • запрос к API возвращает пустой результат, но приложение оставляет статус 200;
    • сервер отправляет HTML главной страницы для любого вложенного пути;
    • компонент ошибки появляется только после выполнения JavaScript;
    • маршрутизатор не имеет отдельного обработчика для отсутствующего пути.

    Проверять нужно не только видимый экран, но и сетевой ответ. В инструментах разработчика браузера следует открыть прямой URL в новой сессии, проверить статус документа, содержание ответа и последующие запросы. Затем адрес проверяется без JavaScript и через инструмент проверки URL поисковой системы. Если неизвестный путь возвращает 200 и содержание главной страницы, это не корректная обработка 404.

    Страница ошибки должна объяснять, что ресурс не найден, и предлагать понятный следующий шаг: перейти в раздел услуг, открыть каталог или вернуться на главную. Но полезный интерфейс страницы ошибки не отменяет правильного HTTP-статуса.

    Canonical для React-маршрутов

    Canonical сообщает поисковой системе предпочтительный URL среди нескольких доступных вариантов. На React-сайте он должен соответствовать фактическому адресу страницы и быть согласован с внутренними ссылками, картой сайта и основным доменом.

    Для индексируемой страницы обычно применяется самоссылочный canonical: страница указывает на собственный нормализованный URL. Если доступны варианты с параметрами, альтернативными протоколами, другим доменом или разными правилами завершающего слеша, canonical должен быть частью общей политики нормализации, а не случайным значением, добавленным отдельным компонентом.

    Google рекомендует задавать canonical в HTML. Его можно добавить JavaScript, но значение после рендеринга не должно противоречить значению в исходном документе. Если скрипт меняет canonical на другой адрес после загрузки, поисковая система получает противоречивые сигналы.

    Типовые ошибки выглядят так:

    • все маршруты используют canonical главной страницы;
    • canonical формируется до того, как известен текущий slug;
    • адрес содержит случайные параметры, которые не должны быть частью канонической версии;
    • http и https считаются разными основными вариантами;
    • адрес с trailing slash и без него используется одновременно;
    • canonical у страницы ошибки указывает на существующую страницу, хотя ресурс отсутствует;
    • после клиентского перехода метаданные изменились, а исходный HTML остался прежним.

    Canonical не превращает дубликат в уникальную страницу и не исправляет неверный маршрут. Сначала нужно определить, какие URL действительно существуют, затем выбрать основную версию и обеспечить согласованную выдачу.

    Метаданные при переходах

    Title, description, canonical и другие данные в head должны соответствовать текущему маршруту. При полной загрузке страницы они формируются сервером или генератором HTML. При переходе без перезагрузки React-приложение должно обновить их так, чтобы пользователь и поисковый робот не получили заголовок предыдущей страницы.

    Особое внимание нужно уделить первому HTML-ответу. Если title и описание появляются только после выполнения JavaScript, поисковая система может обработать страницу иначе, чем пользовательский браузер. Для публичных SEO-страниц надёжнее отдавать основной текст, H1 и важные метаданные уже в исходном HTML.

    Одинаковый шаблон title для всех страниц не помогает различать услуги и статьи. Каждая индексируемая страница должна иметь собственный заголовок, отражающий её содержание. При этом не следует подставлять в title slug, параметры фильтра и другие значения автоматически, если они не описывают отдельную полезную страницу.

    Гидратация и маршруты

    Гидратация — это присоединение логики React к HTML, который уже был сформирован на сервере. React ожидает, что дерево, переданное в hydrateRoot, даст тот же результат, что и серверный рендеринг. Несовпадения считаются ошибками, потому что серверный HTML уже показан пользователю, а клиент пытается подключить обработчики и состояние к существующей структуре.

    Типовые причины ошибок гидратации связаны с различиями между сервером и браузером:

    • проверка window прямо во время рендеринга;
    • чтение localStorage до завершения начального рендера;
    • использование текущей даты или случайного значения;
    • разные данные на сервере и клиенте;
    • некорректная вложенность HTML-элементов;
    • изменение HTML расширением браузера или промежуточным сервисом;
    • различия локали, часового пояса и форматирования.

    Для SEO важен не только текст предупреждения в консоли. При ошибке часть дерева может перерисовываться на клиенте, а первоначальное содержание может отличаться от того, что было отдано сервером. Поэтому основной текст страницы, H1, ссылки и метаданные должны формироваться детерминированно на первом рендере.

    Если значение действительно может отличаться только на клиенте, React допускает отложенное изменение после начальной гидратации. suppressHydrationWarning является ограниченным исключением для неизбежного различия, например времени, и не исправляет несовпадение. React отдельно предупреждает, что при использовании этого механизма несовпадающий текст не исправляется автоматически.

    Как проверять маршрут

    Проверка должна начинаться с списка публичных URL. Для каждого адреса фиксируются ожидаемый компонент, статус, canonical, title, H1, наличие основного текста и ссылки на страницу из других разделов.

    Практическая последовательность выглядит так:

    1. Открыть URL напрямую в новой вкладке, а не перейти на него только из главной страницы.
    2. Проверить ответ документа и убедиться, что существующая страница возвращает 200, перемещённая — 301 или другой согласованный редирект, отсутствующая — 404 или 410.
    3. Посмотреть исходный HTML через View Source и проверить наличие title, description, canonical, H1, текста и ссылок.
    4. Открыть страницу с отключённым JavaScript и определить, остаётся ли доступным критически важное содержание.
    5. Проверить отрендеренный DOM после выполнения JavaScript.
    6. Перезагрузить страницу на вложенном маршруте и проверить отсутствие ошибки приложения.
    7. Нажать кнопку назад и вперёд, открыть ссылку в новой вкладке и скопировать её адрес.
    8. Проверить несуществующий slug и убедиться, что он не превращается в страницу со статусом 200.
    9. Сравнить canonical с фактическим URL, внутренними ссылками и sitemap.
    10. Проверить страницу в Google Search Console и Яндекс.Вебмастере, если сайт добавлен в соответствующие сервисы.

    Для диагностики полезно сравнить три состояния: HTML, который пришёл от сервера, DOM после выполнения JavaScript и результат проверки поисковым роботом. Совпадение только в браузере не доказывает, что маршрут корректно доступен для обхода.

    Когда React Router не подходит

    React Router не является обязательным решением для каждого сайта. Если проект состоит из небольшого числа независимых страниц и не требует сложного клиентского состояния, статические HTML-страницы или серверная маршрутизация могут быть проще для поддержки. Для закрытого кабинета поисковая индексация маршрутов обычно не является целью, поэтому требования к публичному HTML будут другими.

    Клиентская маршрутизация становится рискованной, если команда не контролирует серверные fallback-правила, не тестирует прямое открытие URL и загружает весь текст только после запроса из браузера. В таких условиях проблема возникает не из-за названия библиотеки, а из-за разрыва между адресами приложения и ответами сервера.

    Для публичного сайта услуг маршрутизация подходит, если у каждой страницы есть постоянный URL, сервер или генератор умеет вернуть нужный документ, ссылки остаются обычными href, ошибки получают правильные статусы, а canonical и метаданные формируются для конкретного маршрута.

    Практический пример

    Для сайта веб-студии могут существовать маршруты /services, /services/react-development, /blog/react-router-seo и /contacts. Страница услуги должна открываться напрямую, содержать собственный title, H1, текст, ссылки на связанные материалы и самоссылочный canonical. Ссылка из меню должна вести на адрес через href, а не только вызывать изменение состояния.

    При запросе /services/react-development сервер или статический хостинг должен вернуть HTML этой страницы со статусом 200. При запросе /services/unknown сервер не должен отдавать главную страницу со статусом 200. Если услуга была перенесена на /services/react-development, старый адрес должен вести на новый постоянным перенаправлением.

    После загрузки React может присоединить интерактивность: форму заявки, раскрывающиеся блоки, фильтр или калькулятор. Эти функции не должны быть единственным способом получить название услуги, основной текст и навигацию по сайту.

    Чек-лист публикации

    • У маршрута есть постоянный понятный URL.
    • Прямой запрос к существующему адресу возвращает нужную страницу.
    • Ссылки на публичные страницы используют href.
    • History API не заменяет серверную обработку маршрутов.
    • Существующие страницы возвращают 200.
    • Перемещённые страницы перенаправляются на новый адрес.
    • Неизвестные адреса возвращают 404 или 410.
    • У страницы нет soft 404.
    • Title, description, H1 и основной текст соответствуют маршруту.
    • Canonical совпадает с выбранной основной версией URL.
    • Исходный HTML содержит критически важное содержание.
    • Серверный HTML и первый клиентский рендер совпадают.
    • Вложенные URL проверены после прямой перезагрузки.
    • Страница проверена в инструментах поисковых систем.

    Часто задаваемые вопросы

    Может ли React Router ухудшить SEO?

    Сам маршрутизатор не определяет качество индексации. Проблемы появляются, если публичные URL не обрабатываются сервером, ссылки не имеют href, содержание появляется только после ненадёжного JavaScript или все неизвестные адреса возвращают главную страницу со статусом 200.

    Нужно ли использовать SSR для каждого React-сайта?

    Нет. Для стабильных публичных страниц подходит статическая генерация или предварительный рендеринг. SSR нужен, когда HTML должен формироваться на сервере для каждого запроса, например при часто меняющихся данных. Выбор зависит от содержания, обновляемости и архитектуры проекта.

    Достаточно ли изменить URL через History API?

    Нет. History API меняет адрес и историю браузера, но не создаёт серверный ресурс. Каждый публичный маршрут должен быть доступен при прямом запросе.

    Почему ссылка-кнопка хуже обычной ссылки?

    Кнопка с обработчиком предназначена для действия внутри интерфейса. Обычная ссылка с href даёт браузеру и поисковому роботу адрес назначения, поддерживает открытие в новой вкладке и переход при отключённом JavaScript.

    Какой статус должен быть у отсутствующей страницы?

    Обычно 404. Статус 410 может использоваться для окончательно удалённого ресурса, если замены нет. Возврат 200 для страницы с сообщением «не найдено» создаёт soft 404.

    Нужен ли canonical на каждой странице?

    Для индексируемых страниц обычно задают самоссылочный canonical, если нет иной обоснованной канонической версии. Страница ошибки не должна маскироваться canonical на главную страницу.

    Можно ли задавать canonical только через JavaScript?

    Технически Google может обработать добавленный JavaScript canonical, но предпочтительно задавать его в исходном HTML. Значение после рендеринга не должно противоречить исходному адресу.

    Что делать при ошибке гидратации?

    Найти различие между серверным HTML и первым клиентским рендером. Проверить browser-only API, дату, случайные значения, данные API, локаль, вложенность тегов и изменения HTML промежуточными сервисами.

    Видит ли поисковик страницы, загруженные React?

    Google выполняет JavaScript и использует отрендерированный HTML, но выполнение происходит после обхода и зависит от доступности ресурсов. Содержание в исходном HTML делает страницу быстрее доступной и уменьшает зависимость от рендеринга.

    Как проверить, что маршрут готов к публикации?

    Открыть его напрямую, проверить HTTP-статус, исходный HTML, DOM после рендеринга, ссылки, title, H1, canonical, страницу ошибки и результат проверки URL в поисковых инструментах.

    Нужен сайт для вашего бизнеса?

    Уникальная разработка или быстрый старт — выберите свой путь