Страница удалена.
Пользователь открывает старую ссылку и видит:
Страница не найдена.
Кажется, всё настроено правильно.
Но сервер отвечает:
HTTP/1.1 200 OKДля человека это экран ошибки.
Для поискового робота — успешно существующая страница.
Или другая ситуация.
Старая статья переехала:
/expert/old-urlна:
/expert/new-urlРазработчик делает redirect.
Но использует:
302 Foundхотя перенос постоянный.
В браузере пользователь всё равно попадает туда, куда нужно.
Но поисковой системе отправляется другой смысл:
Перенос временный.
Именно поэтому HTTP-коды — это не техническая формальность, скрытая где-то между Nginx и браузером.
Для поискового робота они отвечают на фундаментальные вопросы:
Страница существует?
Страница переместилась?
Перемещение постоянное?
Перемещение временное?
Страница удалена?
Страница удалена навсегда?
Сервер временно сломан?И если HTML говорит одно, а HTTP — другое, поисковая система вынуждена самостоятельно разбираться в противоречии.
Разберём пять состояний, которые особенно часто влияют на техническое SEO:
301
302
404
410
soft 404И заодно посмотрим, где рядом с ними находятся 200, 503 и 429.
HTTP-код — это ответ сервера о состоянии ресурса
Когда поисковый робот запрашивает:
GET /expert/articleон получает не только HTML.
Сначала приходит примерно такой ответ:
HTTP/1.1 200 OK
Content-Type: text/htmlИ только после этого:
<html>
...
</html>Статус:
200говорит:
Запрос обработан успешно, ресурс существует.
Статус:
404говорит:
Такого ресурса здесь нет.
301:
Ресурс окончательно переехал.
302:
Сейчас ресурс временно находится в другом месте.
410:
Этот ресурс был здесь, но удалён окончательно.
Поэтому SEO начинается ещё до <title>, H1 и canonical.
Если сервер неправильно описывает состояние URL, поисковой системе приходится сначала решить именно эту проблему.
Короткая таблица
| Состояние URL | Правильный ответ |
|---|---|
| Страница существует | 200 |
| Страница навсегда переехала | 301 |
| Перенос действительно временный | 302 |
| URL не существует | 404 |
| Ресурс сознательно удалён навсегда | 410 |
| Сервер временно недоступен | обычно 503 |
| Слишком много запросов | 429 |
Страница визуально отсутствует, но сервер отдаёт 200 | soft 404 — ошибка архитектуры |
Но главное — не запомнить таблицу, а понимать смысл каждого решения.
200 OK: страница действительно существует
Начнём с нормального состояния.
Публичная индексируемая статья:
https://example.ru/expert/api-versioningсуществует и должна участвовать в поиске.
Ожидаем:
HTTP/1.1 200 OK
Content-Type: text/htmlВнутри:
TITLE;
H1;
контент;
canonical;
structured data.Для Яндекса это тоже базовое правило: необходимые страницы сайта должны возвращать 200 OK, а отсутствующие — корректный код ошибки.
Но 200 — не универсальный ответ на всё
Иногда frontend-разработчику проще настроить сервер:
любой URL
↓
index.html
↓
200 OKДля SPA это действительно удобно.
Например:
/login
/account
/projectsобрабатываются клиентским router.
Но вместе с ними сервер начинает отдавать:
/this-page-does-not-exist-at-all
↓
index.html
↓
200JavaScript потом рисует:
Страница не найдена.
Так возникает soft 404.
Что такое soft 404
Soft 404 — это ситуация, когда страница по смыслу является ошибкой или практически пустым документом, но сервер отвечает:
200 OKGoogle прямо определяет soft 404 как ситуацию, когда URL показывает пользователю, что страницы не существует, но возвращает успешный HTTP-статус 200. К soft 404 Google может также отнести пустые или почти пустые документы — например при проблемах базы данных или JavaScript. Такие страницы могут исключаться из поиска.
Яндекс описывает ту же распространённую ошибку: заглушка «страница не найдена» возвращает 200, поэтому робот считает несуществующий URL действующей страницей. Это создаёт лишние документы и замедляет индексирование полезных URL.
Вот классический soft 404
Пользователь открывает:
/expert/nonexistent-articleи видит:
404
Материал не найден.
Перейти на главную.Но реальный HTTP:
HTTP/1.1 200 OKЧисло:
404внутри дизайна не имеет отношения к HTTP-коду.
Можно написать огромными буквами:
404на всю страницу.
Если сервер отправил:
200технически это успешный документ.
Правильный вариант
Можно сохранить красивый интерфейс:
Материал не найден.
Возможно, он был удалён.
Популярные статьи:
...Но HTTP должен быть:
HTTP/1.1 404 Not FoundGoogle отдельно подчёркивает: custom 404 можно сделать удобным и визуально таким же, как остальной сайт, но сервер всё равно должен возвращать настоящий 404.
Soft 404 бывает не только на странице «Не найдено»
Это особенно важно.
Допустим существует:
/product/4812Сервер отвечает:
200Но запрос к API товара упал.
Frontend отрисовал:
Не удалось загрузить товар.или вообще:
<div id="app"></div>без основного содержимого.
Google может увидеть практически пустой документ и классифицировать его как soft 404. В официальной документации среди причин называются проблемы базы данных, отсутствующий JavaScript и незагруженные важные ресурсы.
Поэтому soft 404 особенно опасен для CSR/SPA
Например:
GET /product/4812
↓
200 index.html
↓
JavaScript
↓
GET /api/products/4812
↓
404
↓
frontend показывает «товар не найден»На серверном уровне всё ещё:
200.Лучшее решение — настоящий статус на сервере
Если архитектура позволяет:
/product/not-existing
↓
HTTP 404это наиболее понятная модель.
Google отдельно рекомендует использовать meaningful HTTP status codes и указывает, что для SPA client-side routing soft 404 требует специальной обработки, например перехода на серверный URL, возвращающий настоящий 404, либо как запасного варианта noindex на error page.
Теперь разберём настоящий 404
Код:
404 Not Foundозначает:
Сервер не нашёл запрашиваемый ресурс.
Например существовала опечатка:
/expert/postgesqlвместо:
/expert/postgresqlНикакой страницы /postgesql никогда не было.
Идеальный ответ:
404.404 — это не SEO-наказание
Иногда владельцы сайтов боятся:
На сайте есть 404 — поисковик подумает, что сайт плохой.
Корректный 404 для реально отсутствующего URL — нормальная работа HTTP.
Проблема не в самом существовании 404.
Проблема, например:
внутреннее меню ведёт на 404;или:
важная статья случайно стала 404;или:
в sitemap тысячи удалённых URL.Но если кто-то запросил:
/random-nonsense-xyzтакой URL и должен вернуть 404.
Google рекомендует возвращать 404 или 410, если контент удалён и подходящей замены нет.
Яндекс аналогично рекомендует настоящий 404 для несуществующих страниц.
Красивый 404 и настоящий 404 прекрасно совместимы
Например:
HTTP/1.1 404 Not Found
Content-Type: text/htmlа HTML:
Такой страницы нет.
Возможно, ссылка устарела.
[Экспертный центр]
[Услуги]
[Главная]Это хороший UX.
Статус нужен роботу и клиенту.
Интерфейс — человеку.
Когда использовать 404
Хорошие сценарии:
случайный несуществующий URL;
удалённая страница без прямой замены;
невалидный slug;
несуществующая сущность.Например:
/expert/article-that-never-existed
→ 404или:
/products/999999999
→ 404если такого товара действительно нет и не предусмотрена другая продуктовая политика.
Но не используйте 404, если страница переехала
Представим была статья:
/expert/api-oldМы просто изменили slug:
/expert/api-versioningСтарый URL уже не должен отдавать:
404.У страницы есть ясная замена.
Поэтому нужен:
301.301 Moved Permanently
301 означает:
Этот ресурс навсегда перемещён на другой URL.
Например:
/expert/old-api-guideпереехал на:
/expert/api-versioningОтвет:
HTTP/1.1 301 Moved Permanently
Location: https://example.ru/expert/api-versioningЧто происходит для пользователя
Он открывает:
/old-api-guideи браузер автоматически отправляет его:
/api-versioning.Что происходит для поисковой системы
Google рассматривает постоянный redirect как сильный сигнал, что конечный URL должен стать canonical. 301 и 308 относятся к постоянным redirects.
Яндекс также рекомендует 301 для постоянного изменения адреса страницы: старый документ перестаёт быть целевой страницей поиска, а робот обрабатывает новый URL.
Когда 301 — правильный выбор
Например:
сменился slug;изменена структура раздела;HTTP → HTTPS;www → без www;старый товар заменён прямым новым аналогом;две статьи действительно объединены
в одну более полную.Особенно важны семантически близкие замены
Было:
/expert/seo-canonical-oldСтало:
/expert/canonical-dubli-stranic-seoЭто один и тот же материал с новым URL.
301 естественен.
Но 301 не должен быть универсальной заменой 404
Представим удалено:
/expert/akciya-2019Прямой современной замены нет.
Разработчик думает:
Чтобы не терять SEO, отправим всех на главную.
Получаем:
/akciya-2019
↓ 301
/Но главная страница не является заменой материала про акцию 2019 года.
Redirect должен иметь смысл для пользователя
Хороший вопрос:
Пользователь, пришедший по старому URL, действительно ожидал увидеть то, что находится на новом?
Если:
да301 оправдан.
Если:
нетне нужно искусственно перенаправлять всё подряд.
В официальных рекомендациях Google логика именно такая: если страница перемещена или есть ясная замена — используйте 301; если контент удалён и аналогичной замены нет — 404 или 410.
Не делайте огромных redirect-цепочек
Плохо:
/article-v1
↓ 301
/article-v2
↓ 301
/article-v3
↓ 301
/article-v4Если текущий URL:
/article-v4лучше:
/article-v1 → /article-v4
/article-v2 → /article-v4
/article-v3 → /article-v4Почему это лучше
Меньше:
сетевых переходов;
неопределённости;
задержки;
точек конфигурационной ошибки.И понятнее архитектура URL.
Нужно обновлять и внутренние ссылки
Плохая схема:
Карточка статьи
↓
/old-url
↓ 301
/new-urlRedirect спасает старые внешние ссылки.
Но собственный сайт уже должен ссылаться:
сразу на /new-url.Sitemap тоже должен содержать конечный URL
Не:
<loc>
https://example.ru/old-url
</loc>если он возвращает 301.
А:
<loc>
https://example.ru/new-url
</loc>Sitemap должен описывать актуальные страницы сайта, а не историю redirects.
Теперь 302 Found
302 означает временное перенаправление.
Концептуально:
Сейчас ресурс находится здесь, но исходный URL остаётся его постоянным адресом.
Пример
Есть:
/campaignНа несколько дней пользователей нужно отправлять:
/campaign-maintenanceпосле чего вернуть старую страницу.
В такой модели временный redirect имеет смысл.
Главное отличие от 301 — намерение
301:
переехали навсегда.302:
временная ситуация,
исходный URL ещё понадобится.Для Google это различие имеет SEO-смысл
В актуальной документации Google постоянные redirects используются как сигнал, что target должен стать canonical.
Временные redirects, включая 302 и 307, не используются таким же образом как сигнал постоянной смены canonical; исходный URL предполагается временно сохранённым как основной, хотя целевой URL может индексироваться при наличии других сигналов.
У Яндекса детали обработки отличаются
Яндекс описывает 302 как временное размещение ресурса по другому адресу и рекомендует использовать его именно для временных scenarios — например A/B-тестов или обслуживания. Для постоянного перемещения Яндекс рекомендует 301.
Именно поэтому практическое правило для обеих поисковых систем одинаковое:
не используйте 302 для постоянного переноса только потому, что браузер всё равно открывает нужную страницу.
Одна из самых частых SEO-ошибок
Разработчик пишет:
res.redirect('/new-url');Framework по умолчанию отдаёт:
302.А перенос на самом деле постоянный.
Приложение визуально работает идеально.
Через полгода всё ещё:
302.Значит redirect status нужно указывать явно
Например:
301для permanent migration.
Не полагаться на default framework behavior.
Когда 302 действительно нужен
Например:
временная промо-версия;A/B-сценарий;временный альтернативный маршрут;страница ненадолго перенесена,
но исходный URL вернётся.Когда 302 почти наверняка неправильный
Например:
старый slug заменён навсегда;новая структура сайта;сменился домен;HTTP окончательно переводится на HTTPS.Там нужен постоянный redirect.
Теперь 410 Gone
410 более конкретен, чем 404.
404 говорит:
Ресурс не найден.
410:
Ресурс сознательно удалён и больше не существует.
На сайте была временная страница:
/event-2024-registrationМероприятие окончательно закончилось.
Страница больше никогда не должна возвращаться.
Прямой замены нет.
Можно использовать:
410 GoneЯндекс прямо определяет 410 как permanently deleted resource
То есть ресурс окончательно удалён с сайта; если он не удалён, а переехал, рекомендуется 301.
Google для удалённого контента без замены разрешает и 404, и 410: оба сообщают, что страницы больше нет и она не должна индексироваться.
Что выбрать: 404 или 410?
Практически:
404отлично подходит для:
неизвестного URL;
ошибки в адресе;
удалённого ресурса,
для которого не требуется
специально подчёркивать окончательное удаление.410 логично использовать, когда приложение точно знает, что ресурс существовал и был сознательно удалён навсегда.
Например в БД есть tombstone:
article_id = 1842
status = permanently_deletedТогда:
410семантически очень чист.
Но не нужно превращать выбор 404 vs 410 в SEO-мистику
Иногда встречается утверждение:
410 гарантированно удаляется из Google намного быстрее, поэтому всегда используйте его.
Официальная текущая документация Google рекомендует оба кода для удалённого контента без замены и не даёт оснований строить универсальную стратегию вокруг обещания конкретной разницы в скорости удаления.
Поэтому выбирать стоит прежде всего по смыслу системы.
Хорошая модель
URL никогда не существовал
→ 404URL удалён,
но приложение не ведёт
отдельную семантику удаления
→ 404ресурс сознательно
и окончательно удалён
→ 410ресурс переехал
→ 301Почему нельзя оставлять удалённую страницу с 200
Допустим статья удалена.
Вместо неё CMS отдаёт:
200 OKи текст:
Материал был удалён.Мы создали soft 404.
Яндекс прямо предупреждает, что такое поведение заставляет робота считать ошибочный URL действующей страницей и может замедлять индексирование полезных документов.
Google также может исключить такую страницу как soft 404.
Что делать с удалённым товаром
Это интереснее статей.
Представим товар:
/products/iphone-15-blackбольше не продаётся.
Нужно понять почему.
Сценарий A: товар временно закончился
Через неделю он вернётся.
Не нужно:
404.Страница всё ещё полезна.
Можно оставить:
200 OKи показать:
Нет в наличии.
Сообщить о поступлении.
Похожие товары.URL остаётся реальным документом.
Сценарий B: товар снят, но есть прямой новый аналог
Например старая модель полностью заменена:
/model-2025
→
/model-2026Если для пользователя это действительно логичная замена:
301может быть хорошим решением.
Сценарий C: товар снят навсегда, замены нет
Тогда:
404или:
410.В зависимости от модели сайта.
Не отправляйте все снятые товары на каталог
Плохо:
/old-phone
↓ 301
/smartphonesесли категория не является реальной заменой конкретного товара.
Пользователь ожидал один товар, а оказался на огромном списке.
То же самое касается удалённых статей
Было:
/expert/old-articleЕсть новая статья, полностью заменяющая её:
301 → /expert/new-articleНет прямой замены:
404/410.Не перенаправляйте всё на главную «для сохранения SEO»
Это очень распространённая идея:
любой старый URL
↓
301
↓
/Так получается:
удалённая статья
→ главная
старый товар
→ главная
несуществующий slug
→ главная
опечатка
→ главнаяСтруктурного смысла в таких redirects нет.
Что поисковику вообще делать с такой схемой?
Запрошен документ:
/how-to-configure-postgresqlА сервер утверждает:
Его постоянная замена — корпоративная главная страница.
Содержательно это неправда.
Поэтому redirects нужно проектировать по принципу реальной эквивалентности или понятного переноса, а не просто желания избежать 404.
Soft 404 может появиться и через redirect
Например любой отсутствующий URL:
/random-xyzавтоматически отправляется:
302 → /или:
301 → /Мы по-прежнему маскируем отсутствие ресурса, только теперь через redirect.
Для реально отсутствующего URL без эквивалентной замены правильнее честный 404/410.
Страница не найдена — это полезная информация
Иногда разработчики воспринимают 404 как неудачу сайта.
Но HTTP должен честно описывать состояние системы.
Страницы нет
→ 404.Это лучше, чем притворяться:
Страница существует
→ 200,или:
Она переехала на главную
→ 301.404 в sitemap — уже другая проблема
Сам 404 нормален.
Но если sitemap.xml содержит:
1000 URLи:
300 из них → 404,сайт одновременно сообщает поисковику:
Вот мои важные страницы.
и:
30% из них не существуют.
Такой sitemap нужно исправлять.
В Sitemap должны находиться текущие indexable URLs
Обычно это:
200;
canonical;
актуальные.После удаления страницы:
убираем URL из sitemap.Если есть replacement:
добавляем новый URL.Старые внешние ссылки при этом не нужно удалять вручную
Если старый URL имеет прямую замену:
301продолжает принимать внешний traffic.
Именно для этого redirect и нужен.
Что происходит с внутренними ссылками
После удаления или миграции нужно искать:
<a href="/old-url">по всему сайту.
Если redirect существует:
сайт технически не сломан.Но внутренняя архитектура всё равно плохая:
internal link
↓
301
↓
final URL.Собственные ссылки стоит обновить сразу на финальный адрес.
404 и внутренние broken links
Например статья содержит:
Подробнее:
старый материално ссылка ведёт:
404.Сам статус правильный.
Неправильна ссылка на него.
Яндекс Webmaster отдельно предоставляет диагностику broken links именно для таких ситуаций.
Не лечите broken link неправильным HTTP-кодом
Проблема:
внутренняя ссылка ведёт
на удалённую страницу.Решение:
исправить ссылку.Не:
заставить удалённую страницу
возвращать 200.Теперь важный сосед: 503 Service Unavailable
Хотя тема статьи про 301/302/404/410, без 503 легко допустить опасную ошибку.
Представим deployment.
База временно недоступна.
Главная страница вместо нормального содержимого возвращает:
404.Это неправильно.
Страница не исчезла.
Сервис временно не способен её выдать.
Для временной серверной проблемы нужен другой смысл
Например:
503 Service Unavailableговорит:
Ресурс сейчас временно недоступен.
Не:
Этого URL больше нет.
Почему это критично
Google отдельно предупреждает не использовать 404/403 для rate limiting или временных серверных проблем: 4xx-состояния означают проблему ресурса/запроса, а для перегрузки предназначены другие ответы, включая 429, 500 и 503 в соответствующих ситуациях.
Яндекс также не рекомендует маскировать server overload кодами отсутствующих документов и указывает, что 429 и 5xx сигнализируют роботу о проблемах доступности сервера.
То есть ошибка БД не должна превращать все статьи в 404
Плохой код:
const article = await db.find(slug);
if (!article) {
return res.status(404).render('not-found');
}Что если:
db.find()не вернул:
null,а произошёл timeout?
Это два разных состояния.
Нужно различать
Запрос к БД успешен,
article отсутствует
→ 404и:
БД недоступна
→ 5xx/503Иначе временный инфраструктурный сбой начинает сообщать поисковикам:
Все наши статьи удалены.
Это особенно важно после deployment
Представим:
12:00
релиз
12:01
migration ещё не закончилась
12:02
Googlebot приходитЕсли сервер отдаёт:
404на реальные страницы, мы передаём совершенно неправильный сигнал.
429 — тоже отдельное состояние
429 Too Many Requestsозначает:
Клиент делает слишком много запросов.
Не:
страницы нет.Поэтому нельзя бороться с crawler load так:
Googlebot слишком активен
→ отдаём ему 404.Google отдельно предупреждает против такой практики.
Отдельная выдача статусов Googlebot тоже опасна
Например:
пользователь → 200
Googlebot → 410чтобы «сэкономить crawl».
Google прямо не рекомендует подобное различие: оно создаёт риск cloaking-подобного поведения и сложных ошибок.
Серверная семантика URL должна быть одинаковой и понятной.
Как HTTP-коды связаны с canonical
Представим:
/old-urlимеет:
<link rel="canonical" href="/new-url">но продолжает возвращать:
200.Если old URL больше вообще не нужен, намного понятнее:
301 → /new-url.Google считает redirect сильным canonicalization-сигналом, как и rel="canonical", но redirect одновременно убирает необходимость поддерживать старую страницу как отдельный документ.
Простая логика выбора
Если:
Два URL должны продолжать существовать, но описывают почти один документ.
Тогда:
canonical.Если:
Старый URL больше не должен существовать как самостоятельная страница.
Тогда:
301.Если:
Документа больше нет и замены нет.
Тогда:
404/410.302 здесь не подходит
Если вы уверены:
старый URL больше никогда
не станет основным,слово:
временноуже неправильно описывает архитектуру.
Важный пример: переименование рубрики
Было:
/blog/articleСтало:
/expert/articleНавсегда.
Настраиваем:
/blog/article
↓ 301
/expert/articleНеправильно
302«пока всё не устаканится».
Если архитектурное решение уже постоянное, поисковой системе стоит сообщать именно это.
Пример: временный эксперимент
Основная страница:
/pricesНа неделю запускается альтернативная:
/prices-testПотом всё вернётся обратно.
Здесь temporary redirect действительно может быть осмыслен:
302.Но для A/B-теста URL иногда вообще можно не менять
Это уже зависит от архитектуры эксперимента.
Главное — не использовать постоянную семантику для временного процесса и наоборот.
Что делать с фильтрами и параметрами
Например:
/catalog?sort=priceне обязательно требует redirect.
URL может существовать и возвращать:
200.Если это альтернативное представление той же категории, canonical может указывать на базовый URL.
HTTP-статусы и canonical решают разные задачи.
Не пытайтесь заменить canonical редиректом без необходимости
Если пользователь специально выбрал:
sort=price,redirect на:
/catalogможет сломать функцию сортировки.
То есть:
200 + canonicalможет быть правильнее.
А вот tracking-параметр можно иногда вообще очистить redirect’ом
Например:
/article?utm_source=...Но обычно его сохраняют для analytics и используют canonical на чистый URL.
Главное — чтобы выбранная политика была последовательной.
Разберём несколько практических кейсов
Кейс 1. Изменили slug статьи
Было:
/expert/api-oldСтало:
/expert/api-versioningРешение:
301.Кейс 2. Статья удалена без замены
/expert/obsolete-articleРешение:
404или:
410.Кейс 3. Материал окончательно удалён по решению редакции
И система явно знает:
permanently_deleted = true.Логичный вариант:
410.Кейс 4. Страница временно переехала
Исходный URL скоро снова станет основным.
Решение:
302.Кейс 5. Неизвестный slug в SPA
/expert/random-abcUI показывает:
Страница не найдена.Но HTTP:
200.Это:
soft 404.Нужно добиться настоящего 404 либо корректной альтернативной indexing policy для архитектуры SPA.
Кейс 6. База данных временно недоступна
Реальная статья есть.
Просто backend не может её загрузить.
Не:
404.А:
5xx / 503в зависимости от характера сбоя.
Кейс 7. Товар временно закончился
Страница остаётся полезной.
200.Кейс 8. Товар навсегда заменён новой моделью
Есть очевидный successor.
301.Какие ошибки особенно часто встречаются в Nginx
Например:
try_files $uri /index.html;для SPA.
В результате:
/anything-at-allполучает:
index.html
+
200.Для application routes это удобно.
Для несуществующих SEO routes — опасно.
Поэтому router и Nginx должны договариваться
Например публичные SSR routes:
/expert/*
/services/*
/portfolio/*должны уметь возвращать настоящий status.
Не просто падать в универсальный SPA shell.
Ещё одна распространённая ошибка
Nginx:
error_page 404 /index.html;а внутренняя конфигурация меняет ответ на:
200.Визуально пользователь видит приложение.
Но HTTP-семантика потеряна.
Проверяйте не браузером, а HTTP-запросом
Например:
curl -I https://example.ru/does-not-existОжидаем:
HTTP/2 404Для redirect
curl -I https://example.ru/old-urlОжидаем:
HTTP/2 301
location: https://example.ru/new-urlИ отключайте автоматическое следование redirect при тесте
Иначе инструмент покажет конечный:
200и разработчик может не заметить, что по дороге были:
302
→ 301
→ 301.HTTP-тесты очень хорошо автоматизируются
Например:
known page
→ 200
old permanent URL
→ 301
temporary route
→ 302
missing page
→ 404
permanently removed resource
→ 410CI может проверять это при каждом релизе.
Пример тестового контракта
expect(
await status('/expert/article')
).toBe(200);
expect(
await status('/expert/old-article')
).toBe(301);
expect(
await status('/expert/definitely-missing')
).toBe(404);А затем отдельно проверяется:
Location header.Но одного известного 404 недостаточно
Особенно у SPA.
Нужно сгенерировать случайный URL:
/seo-test-does-not-exist-a8f392Почему?
Потому что заранее известный:
/404может быть специально настроен правильно.
А случайный маршрут всё ещё:
200.Это очень хороший production smoke test
После deployment:
GET /seo-test-random-UUIDожидаем:
404.Если пришёл:
200,release потенциально создаёт soft 404.
То же самое полезно для старого redirect
GET /known-old-urlбез автоматического follow.
Ожидаем:
301.И:
Location = точный конечный URL.Проверяем отсутствие redirect chains
Тест может пройти redirects самостоятельно.
Например:
old
↓
middle
↓
finalи зафиксировать:
redirect hops = 2.Для большинства обычных миграций можно принять внутреннее правило:
redirect hops <= 1.Это уже SEO as Code
Не:
После релиза глазами откроем пару страниц.
А:
HTTP semantics
=
автоматический контракт.Какие URL должны быть в sitemap
Обычно:
финальные;
200;
indexable;
canonical.Не нужно добавлять:
301;
302;
404;
410.Sitemap должен описывать актуальное содержимое сайта.
Иначе появляется странный сигнал
Sitemap:
Пожалуйста, обходите этот URL.
Server:
404.или:
301.Лучше заранее удалить такой URL из генератора sitemap.
CMS должна обновлять sitemap автоматически
Если статья:
published→ появляется.
Если:
deleted→ исчезает.
Если slug изменился:
старый URL → 301
новый URL → sitemap.Не нужно каждый раз вручную редактировать XML.
Что происходит после удаления страницы из поиска
Нельзя ожидать:
поставил 404
↓
через минуту URL исчез.Поисковой системе сначала нужно снова посетить URL и обработать новый статус.
Поэтому некоторое время старый адрес ещё может быть известен системе.
Не возвращайте старую страницу в 200 только потому, что она всё ещё видна в Search Console
Правильный статус уже настроен.
Нужно дать crawler время обновить состояние.
То же относится к 301
После миграции поисковой системе нужно:
обойти старый URL;
увидеть redirect;
обойти новый;
переобработать canonical signals.Это не синхронная database transaction.
Яндекс рекомендует сохранять permanent redirect достаточно долго
В актуальной документации Яндекса для 301 указано сохранять redirect как минимум шесть месяцев, чтобы поисковые системы корректно обработали перенос.
На практике для ценных старых URL часто вообще нет причины удалять рабочий redirect, если он недорог в поддержке.
301 не нужен только «на пару недель для Google»
Пока:
старые ссылки;
закладки;
внешние публикациипродолжают существовать, redirect всё ещё приносит пользу пользователям.
HTTP-коды важны и для API, но SEO-контекст другой
Например:
/api/project/123может возвращать:
404.Но если API закрыт от поиска и не является публичной страницей, это не SEO-документ.
Не нужно автоматически пытаться индексировать каждый HTTP route сайта.
Нас интересует прежде всего публичный URL-space
Например:
/
/services/*
/expert/*
/portfolio/*
/pricesИменно там status semantics особенно важна для поискового индекса.
Что отображать пользователю на 404
Можно сделать страницу полезной:
Такой страницы больше нет.
Возможно, адрес изменился.
[Перейти в Экспертный центр]
Популярные материалы:
...Это улучшает UX.
Но:
HTTP status = 404.остаётся неизменным.
Не нужно бояться ссылок на 404-странице
Custom 404 может иметь:
меню;
логотип;
поиск;
ссылки;
footer.Это совершенно нормально.
Статус и UI решают разные задачи.
А вот canonical на 404 обычно не спасает ситуацию
Например:
404 page
canonical → /не превращает несуществующий URL в дубль главной.
Если документ не существует:
404/410уже описывает нужное состояние.
Не используйте redirect только для того, чтобы «убрать 404 из отчёта»
Например система показывает:
500 старых URL → 404.Разработчик автоматически создаёт:
500 redirects → /Теперь отчёт визуально чище.
Но архитектура стала хуже.
Сначала классифицируйте каждый класс URL
Например:
старые slug с новыми аналогами
→ 301.удалённые материалы без замены
→ 404/410.опечатки
→ 404.устаревшие category paths
с прямой новой категорией
→ 301.Не:
всё → homepage.404 и 410 не должны быть в robots.txt только ради удаления из индекса
Если поисковому роботу нужно узнать:
эта страница теперь 404/410,он должен иметь возможность запросить URL и получить соответствующий статус.
Блокировка crawling может мешать ему увидеть новое состояние.
Особенно важно это после удаления ранее индексируемой страницы
Пусть робот получит:
404/410.И сможет обновить индекс.
Отдельно про robots.txt самого сайта
Ошибка:
/robots.txt → 404не всегда трактуется так же, как обычный удалённый документ, поэтому инфраструктурные endpoints нужно тестировать отдельно.
Главная мысль здесь проще:
не применяйте к системным ресурсам механически те же правила, что к контентным страницам.
Как выглядит здоровая схема удаления
Страница:
/expert/oldрешено удалить.
Если есть замена:
/expert/old
↓ 301
/expert/newВнутренние ссылки:
→ /expert/new.Sitemap:
только /expert/new.Если замены нет:
/expert/old
↓ 404/410.Внутренние ссылки удалены или исправлены.
Sitemap больше не содержит URL.
Как выглядит нездоровая
/expert/old
↓ 200
«Статья удалена»Sitemap:
всё ещё содержит /expert/old.Внутренние ссылки:
всё ещё ведут туда.Canonical:
→ /.Здесь почти каждый слой противоречит другому.
HTTP-коды должны быть согласованы со всем SEO-контрактом
Для существующей страницы:
200
+
self-canonical
+
sitemap
+
internal linksДля permanently moved:
301
+
old URL удалён из sitemap
+
internal links обновлены
+
new URL = 200.Для deleted:
404/410
+
нет в sitemap
+
нет внутренних ссылок.Для temporary redirect:
302
+
есть понятная причина временности
+
исходный URL остаётся частью архитектуры.Очень полезна таблица URL-policy
Например в проекте:
| Тип URL | HTTP |
|---|---|
| Опубликованная статья | 200 |
| Неизвестная статья | 404 |
| Permanently deleted | 410 |
| Старый slug | 301 |
| Временный preview redirect | 302 |
| Сервис временно недоступен | 503 |
Это уже можно превратить в automated tests.
Что мониторить в production
Очень полезно считать:
200 rate;
301 rate;
302 rate;
404 rate;
5xx rate.Но сами цифры нужно интерпретировать.
Рост 404 может означать
сломанные внутренние ссылки;внешний бот перебирает мусорные URL;после deployment исчезли реальные routes;удалена большая группа страниц.Это совершенно разные ситуации.
Поэтому нужна разбивка по route group
Например:
404 /expert/*резко выросли после релиза.
Это серьёзно.
А:
404 /wp-admin/*на Node.js-сайте могут просто означать автоматическое сканирование ботами.
Точно так же внезапный рост 302 может обнаружить ошибку
Предполагалось:
301.Но framework после обновления начал отдавать:
302.Поэтому метрики статусов полезны не только backend-разработчику, но и SEO.
После каждого deployment полезен небольшой smoke-test
Например:
/ → 200
/expert/known-article → 200
/expert/old-slug → 301
/definitely-does-not-exist → 404
/robots.txt → expected
/sitemap.xml → 200Несколько запросов способны поймать очень серьёзный regression.
Например ошибка SPA fallback
После обновления Nginx:
/definitely-does-not-existвнезапно:
404 → 200.Smoke-test сразу падает.
До того, как Google или Яндекс успеют накопить тысячи soft 404.
Или ошибка старого URL
Ожидалось:
301получили:
302.Deployment можно остановить ещё до принятия релиза.
Это и есть смысл SEO как кода
Статус страницы не должен зависеть от того, заметил ли разработчик надпись в DevTools.
Он является проверяемым invariant.
Что показывают поисковые инструменты
Google Search Console способен показывать:
Not found (404);
Soft 404;
Page with redirect;
Server error.Эти состояния полезны как внешний взгляд Google на сайт.
Но искать причину всё равно нужно на уровне реального HTTP и rendering.
Яндекс Вебмастер также диагностирует HTTP-проблемы
В частности:
404;
redirects;
server errors;
soft 404-подобные ошибки.И рекомендует проверять реальный серверный код для несуществующих страниц.
Главная ошибка — начинать лечение с SEO-текстов
Представим статья исчезла из поиска.
Команда:
переписывает TITLE;
добавляет H2;
увеличивает текст;А реальная проблема:
HTTP 302 → /login.Никакое количество текста не исправит HTTP-контракт.
Поэтому диагностика начинается с самого нижнего уровня
DNS
↓
HTTP
↓
status
↓
headers
↓
HTML
↓
canonical/noindex
↓
content
↓
indexingНе наоборот.
Практическая схема принятия решения
Страница больше не открывается по старому URL.
Сначала спрашиваем:
Есть ли у содержимого новый постоянный URL?
Если да:
301.Если нет:
Страница временно находится в другом месте и вернётся?
Если да:
302.Если нет:
Ресурс сознательно удалён навсегда и система это знает?
Если да:
410.В остальных обычных случаях отсутствующего ресурса:
404.А если UI показывает ошибку, но ответ:
200исправляем:
soft 404.Схема в одном блоке
URL существует?
/ \
да нет
│ │
200 Есть замена?
/ \
да нет
│ │
Постоянная? Удалён
/ \ навсегда?
да нет / \
│ │ да нет
301 302 410 404И отдельно:
UI говорит «нет страницы»
+
HTTP 200
=
soft 404Чего не нужно делать
Не перенаправлять каждый 404 на главную
Это не делает главную заменой отсутствующего документа.
Не использовать 302 для постоянных миграций
Если решение постоянное — и HTTP должен говорить об этом.
Не делать 404 для временного server outage
Страница не исчезла.
Сервис временно не способен её отдать.
Не возвращать 200 для красивой страницы ошибки
Дизайн не заменяет HTTP.
Не держать redirected и deleted URLs в sitemap
Sitemap должен описывать актуальные документы.
Не оставлять внутренние ссылки на redirect и 404
Redirect нужен прежде всего для внешней истории и старых адресов, а не как постоянная часть собственной навигации.
Не использовать 410 как «магический ускоритель SEO»
Используйте его, когда семантика действительно:
ресурс удалён окончательно.Практический production checklist
Перед релизом стоит автоматически проверить:
- индексируемые публичные страницы возвращают
200; - случайный несуществующий URL возвращает настоящий
404; - custom 404 сохраняет HTTP
404; - permanently deleted URLs возвращают выбранный проектом
404или410; - старые URL с прямой заменой возвращают
301; - временные redirects действительно возвращают
302/307, а не используются вместо permanent migration; - permanent redirects ведут сразу на конечный
200; - нет лишних redirect chains;
- redirect target не возвращает
404,noindexили ещё один ошибочный redirect; - удалённые и redirected URL отсутствуют в Sitemap;
- внутренние ссылки ведут сразу на конечные URL;
- сбой БД/API не превращает существующие страницы в
404; - temporary server outage имеет server-error semantics, а не «страница исчезла»;
- SPA fallback не создаёт
200на случайных несуществующих маршрутах; - Search Console и Яндекс Вебмастер не показывают неожиданный рост soft 404 и HTTP errors.
Если такой контракт проверяется автоматически, большая часть SEO-проблем со статусами исчезает ещё до production.
Почему это особенно важно для динамических сайтов
На статическом сайте:
50 HTML-файлов.Состояние каждого относительно понятно.
В динамической системе URL формируются из:
БД;
CMS;
slug;
route;
status;
permissions;Одна ошибка общего router способна изменить статус:
10 000 URL.Например редакционная система
Статья:
draftне должна вести себя так же, как:
published.Можно определить явную политику.
Например:
published
→ 200deleted
→ 410unknown slug
→ 404old slug
→ 301 current slugТеперь HTTP является отражением business state.
Это намного лучше универсального
всё → 200 index.html.HTTP-код можно считать частью state machine контента
Например:
DRAFT
↓ publish
PUBLISHED
↓ rename
OLD_URL → 301
NEW_URL → 200
↓ delete
DELETED → 410Тогда SEO-поведение становится прямым следствием жизненного цикла материала.
Это особенно хорошо тестируется
Создаём статью.
Ожидаем:
200.Меняем slug.
Ожидаем:
old → 301
new → 200.Удаляем.
Ожидаем:
410.Именно так SEO перестаёт быть набором ручных настроек.
Что действительно важно запомнить
301 не означает:
Хороший redirect для SEO.
Он означает:
Перенос постоянный.
302:
Перенос временный.
404:
Такой ресурс не найден.
410:
Ресурс удалён окончательно.
200:
Ресурс существует и успешно отдан.
Soft 404:
Сервер сказал 200, но сама страница фактически говорит обратное.Если выбирать статус именно по этому смыслу, большая часть SEO-решений становится удивительно простой.
Вместо вывода
Поисковой системе не нужен красивый интерфейс ошибки.
Ей нужен честный ответ сервера.
Если страница существует:
200.Если переехала навсегда:
301.Если переместилась временно:
302.Если отсутствует:
404.Если сознательно удалена навсегда:
410.Если сервер показывает:
«Страница не найдена»но отправляет:
200,это уже soft 404 — противоречие между техническим состоянием URL и содержимым страницы.
Именно такие противоречия особенно опасны для современных SPA, CMS и динамических редакционных систем.
Правильную архитектуру лучше строить не вокруг вопроса:
Какой код больше нравится Google?
А вокруг другого:
Что на самом деле произошло с этим ресурсом?
Существует?
Перенесён?
Временно перенесён?
Удалён?
Временно недоступен?После этого HTTP-код выбирается почти автоматически.
А затем вся остальная SEO-система должна подтверждать тот же смысл:
HTTP
+
canonical
+
sitemap
+
internal links
+
indexing policy.Когда эти сигналы согласованы, поисковому роботу не приходится угадывать состояние сайта.
И техническое SEO становится значительно предсказуемее.