Skip to main content
Назад к блогу
3 мин чтения

vercel.json, который молча сломал мой сайтмап на месяц

Одно правило редиректа в vercel.json заставило сайтмап возвращать HTML вместо XML. Google перестал индексировать новые страницы на 4 недели. Как я нашёл и отладил.

performancenext.js

Четыре недели Google не индексировал ни одной новой страницы на сайте клиента. Ни ошибок в Search Console. Ни проблем с краулингом. Сайтмап показывал статус «успешно». Я не заметил, пока не поискал блог-пост по точному названию и не получил ноль результатов.

Корневая причина — одна строка в vercel.json.

Симптом

Я опубликовал 3 новых блог-поста за месяц. Ни один не появился в Google. Старые посты продолжали ранжироваться нормально. Сайт был здоров — ни 500 ошибок, ни проблем с деплоем, быстрая загрузка.

Я проверил Google Search Console:

Последняя строка была подсказкой. Google закраулил сайтмап месяц назад и не вернулся. Но статус сайтмапа говорил «успешно». Почему Google перестал бы рекраулить сайтмап, который он успешно обработал?

Расследование

Шаг 1: Я открыл URL сайтмапа в браузере.

https://client-site.com/sitemap.xml

Отрендерилась главная страница. Не XML — настоящая HTML-главная.

Шаг 2: Проверил curl-ом, чтобы исключить браузерные редиректы.

curl -v https://client-site.com/sitemap.xml
< HTTP/2 200
< content-type: text/html; charset=utf-8

URL сайтмапа вернул 200 с text/html. Сайтмап отдавался как HTML-страница. Google «успешно» его забрал, увидел HTML и молча перестал пытаться парсить как сайтмап.

Шаг 3: Я проверил vercel.json.

Блок rewrites исключал sitemap из перезаписи URL. Но блок redirects — нет. Редиректы выполняются до реврайтов. /sitemap.xml перехватывался редиректом и перенаправлялся на /en/sitemap.xml.

/en/sitemap.xml не существовал. Next.js рендерил catch-all 404 (который возвращал 200 из-за отдельной проблемы — неправильно настроенной not-found страницы). Google видел 200 HTML-ответ и отмечал сайтмап как «обработан».

Фикс

Два изменения:

  1. Добавил sitemap и robots в regex-исключение редиректов (не только реврайтов)
  2. Исправил not-found страницу, чтобы реально возвращала 404-статус

После деплоя:

curl -I https://client-site.com/sitemap.xml
HTTP/2 200
content-type: application/xml

Корректно. XML-сайтмап отдаётся напрямую из Next.js app/sitemap.ts.

Почему не поймал раньше

  1. Vercel деплоит молча. Нет валидации vercel.json против твоих реальных роутов. Правило редиректа было технически валидным — просто матчило больше URL, чем планировалось.

  2. Google Search Console сказал «успешно». 200-ответ с HTML — не ошибка для процессора сайтмапов Google. Он просто молча игнорирует не-XML контент. Ни предупреждения, ни алерта.

  3. Старые страницы продолжали ранжироваться. Google уже проиндексировал старый контент. Невидимым был только новый — а это замечаешь через недели.

  4. Локальная разработка не использует vercel.json. next dev игнорирует Vercel-специфичные правила редиректов. Сайтмап работал идеально локально.

Чеклист предотвращения

После этого инцидента я добавил в деплой-пайплайн:

# Smoke-тест после деплоя
SITEMAP_TYPE=$(curl -s -o /dev/null -w "%{content_type}" https://yoursite.com/sitemap.xml)
if [[ "$SITEMAP_TYPE" != *"xml"* ]]; then
  echo "ALERT: Sitemap is not returning XML"
  exit 1
fi

ROBOTS_TYPE=$(curl -s -o /dev/null -w "%{content_type}" https://yoursite.com/robots.txt)
if [[ "$ROBOTS_TYPE" != *"text/plain"* ]]; then
  echo "ALERT: robots.txt is not returning text/plain"
  exit 1
fi

Две проверки curl. 10 секунд на выполнение. Поймали бы это на первом деплое, а не через 4 недели.

Мета-урок

Редиректы и реврайты vercel.json обрабатываются в порядке: headers → redirects → rewrites → файловая система. Если редирект матчится до исключения реврайта — исключение никогда не запускается. А если твой catch-all роут возвращает 200 вместо 404, каждый сломанный редирект становится невидимым — выглядит рабочим, потому что код ответа говорит OK.

Тестируй инфраструктурные роуты (/sitemap.xml, /robots.txt, /api/*) после каждого изменения vercel.json. Не только роуты приложения.


Беспокоишься о тихих SEO-проблемах на своём Next.js-сайте? Напиши — я запускаю пост-деплой проверки на каждом клиентском проекте именно для того, чтобы ловить этот класс невидимых багов.