Перейти к контенту
Neaptidestudio
блог

Sitemap Next.js возвращает 404: четыре проверки в dev и production

Neaptide · 13 октября 2026 г. · 7 мин чтения

Эксперимент на Next.js 15.5.22: неверный адрес sitemap, сбой источника данных и 404 внутри корректного XML. Исправления, исходные результаты и стенд для повторения.

В этой статье
Три наблюдавшихся сбоя: 404 маршрута, 500 из-за источника и 404 страницы внутри карты со статусом 200.

Прежде чем менять настройки sitemap в Next.js, выясните, какой адрес вернул ошибку. Сама карта сайта, источник данных для её генерации и URL товара внутри XML могут ломаться независимо. Один скриншот страницы 404 не показывает, где нужно исправление.

12 октября 2026 года Neaptide проверил четыре сценария на локальном стенде. Неверный адрес sitemap вернул 404; недоступный источник — 500 на адресе карты, поскольку наш обработчик явно выбрасывал исключение; карта со снятым с публикации товаром вернула 200, а сам товар — 404. Исправления сработали и в next dev, и в локальной production-сборке. Различий между режимами в этих сценариях мы не обнаружили.

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

Стенд использует Next.js 15.5.22, React и React DOM 19.2.6, Node v25.2.1 и два вымышленных товара. До замеров мы зафиксировали протокол, код, сборщик данных и lock-файл, установили зависимости в отдельном каталоге и запустили next dev одновременно с next build и next start. Записи товаров отдаёт локальный HTTP-источник. Production-сборка работает локально; это не тест Vercel.

Четыре сценария дают семь вариантов: исправный контрольный и три пары до/после. Два режима и два прогона — 28 ответов sitemap. Все URL из XML проверены отдельно: ещё 36 ответов страниц и две проверки источника. Всего 66 повторных HTTP-наблюдений, а не 66 уникальных URL. Сохранены тела, заголовки и хеши. Проверка XML включает разбор и пространство имён urlset, но не полную валидацию по XSD.

Одного статуса sitemap оказалось недостаточно

Измеренные статусы карты сайта и страниц в контрольном сценарии и трёх парах до/после; dev и production дали одинаковый результат.
Стенд Neaptide, 12 октября 2026 года. Каждая строка объединяет четыре совпавших наблюдения: два режима × два прогона. Прочерк означает, что urlset не удалось получить, а не ноль URL. Статусы страниц приведены в порядке XML.
Стенд Neaptide, 12 октября 2026 года. Каждая строка объединяет четыре совпавших наблюдения: два режима × два прогона. Прочерк означает, что urlset не удалось получить, а не ноль URL. Статусы страниц приведены в порядке XML.
СценарийСостояниеHTTP sitemapURL в XMLHTTP страниц
Статический контрольКонтроль2002200 / 200
Источник данныхДо500——
Источник данныхПосле2002200 / 200
Адрес картыДо404——
Адрес картыПосле2002200 / 200
Снятый товарДо2002200 / 404
Снятый товарПосле2001200

404 источника привёл к 500 в нашем обработчике

Динамическая карта запрашивает локальный JSON. До исправления путь /missing-catalog.json возвращал 404. Обработчик ниже проверяет response.ok и выбрасывает исключение. Поэтому /dynamic-bad/sitemap.xml вернул 500. Результат зависит от нашей обработки ошибки: это не общее правило преобразования 404 в 500 в Next.js.

// lib/catalog.js
export async function fromFeed(path) {
  const response=await fetch(`http://127.0.0.1:8800${path}`,{cache:'no-store'});
  if(!response.ok) throw new Error(`Controlled catalog source returned HTTP ${response.status}`);
  const rows=await response.json();return entries(rows.map(row=>row.slug));
}

Достаточно было заменить путь источника на /catalog.json: /dynamic-ok/sitemap.xml вернул 200 и два доступных товара. Оба варианта уже использовали force-dynamic и cache: 'no-store'. Добавление динамического рендеринга не было проверенным исправлением. В своём приложении сначала сохраните статус источника и изучите серверный журнал, затем решайте, менять ли кеширование.

// app/dynamic-ok/sitemap.js
import {fromFeed} from '../../lib/catalog';
export const dynamic='force-dynamic';
export default async function sitemap(){return fromFeed('/catalog.json');}

Сопоставьте адрес с расположением файла

Файл app/catalog/sitemap.js создал маршрут /catalog/sitemap.xml. Запрос /sitemaps/catalog.xml вернул 404. Запрос настоящего адреса дал 200 без изменений кода. Контрольный app/sitemap.js в корне также вернул 200. Эти пути соответствуют файловой конвенции Next.js. Разбитые карты с generateSitemaps мы не проверяли.

app/sitemap.js          → /sitemap.xml
app/catalog/sitemap.js  → /catalog/sitemap.xml

Карта с кодом 200 может содержать страницу 404

Вариант stale-before включал все редакционные записи, в том числе /products/retired. XML разбирался, карта возвращала 200, но снятый товар — 404. Фильтр published перед генерацией URL оставил одну запись, /products/widget-a, со статусом 200. Мы исключили неопубликованный товар, не создавая редирект и не подменяя его другим.

// app/stale-after/sitemap.js
import {editorialRecords,entries} from '../../lib/catalog';
export default function sitemap(){return entries(editorialRecords.filter(row=>row.published).map(row=>row.slug));}

Флаг published сам по себе не определяет индексируемость. В реальном каталоге также проверьте, что выбраны нужные канонические страницы и они допускают индексацию. Страницы стенда намеренно содержат noindex/nofollow: здесь измеряется доступность маршрутов.

Проследите, на каком адресе возникает ошибка

Начните с точного адреса отправленной карты и GET-запроса. Сохраните статус и тело до перехода по редиректам. Схема ниже — практический порядок диагностики; некорректный XML и сбои только на хостинге указаны как рекомендации, а не дополнительные измеренные сценарии.

Порядок диагностики: 404 карты — проверка маршрута, 5xx — источник и журналы, 200 — разбор XML и проверка адресов loc.
Схема диагностики на основе измеренных сценариев. После 200 всё равно нужно проверить XML и адреса страниц; причины, зависящие от хостинга, не тестировались.
  1. Sitemap возвращает 404: сравните запрошенный путь с фактическим маршрутом и файлом. В S3 помогло исправление адреса.
  2. Sitemap возвращает 5xx: изучите серверную ошибку маршрута и ответ источника. В S2 отсутствующий источник вызывал исключение; исправление его пути устранило сбой.
  3. Sitemap возвращает 200: разберите тело и проверьте пространство имён корневого элемента. Если пришёл HTML или некорректный XML, исследуйте маршрут, формирующий ответ. Такой сбой мы не моделировали.
  4. XML разбирается: запросите адреса loc и проверьте статусы. В S4 это выявило снятый товар, который проверка одной карты пропустила.
  5. Сбой возникает только на хостинге: сравните коммит, путь запроса, переменные окружения и доступность источника с next build и next start. Затем изучите маршрутизацию и журналы деплоя. Наш локальный тест не выявлял ошибок хостинга.

Google рекомендует абсолютные адреса предпочтительных страниц, которые вы хотите видеть в поиске. Отправка карты служит подсказкой и не гарантирует обход. После деплоя проверьте ошибки обработки в отчёте Sitemaps в Search Console: успешный локальный ответ не показывает результат Google.

Повторите проверку на том же стенде

Скачайте архив и следуйте README.txt. Запустите локальный источник, установите закреплённые зависимости и поднимите dev и production на портах 8801 и 8802. Сборщик сохраняет всю матрицу без перехода по редиректам и обхода внешних сайтов. Архив сопоставлен с зафиксированным кодом; повторный запуск его сборщика на исходных работающих серверах подтвердил все 28 результатов sitemap. Это не вторая чистая установка серверов.

Методика, данные и рабочий пример

Ошибки внесены намеренно и помогают разобрать диагностику, но не показывают распространённость проблем. Мы не тестировали живую CMS, сброс кеша, middleware, rewrites, CDN или Vercel и не измеряли индексацию, позиции или цитирование ИИ. Историческое обращение по Next.js RC/Windows/Prisma помогло сформулировать вопрос; этот стенд не воспроизводит и не решает проблему той среды.

частые вопросы

Коротко о главном

Нужно ли добавлять force-dynamic, если sitemap возвращает 404?

Сначала найдите адрес с ошибкой. В нашем тесте оба динамических варианта уже использовали force-dynamic; помогла замена пути источника. Для ошибочного адреса карты достаточно было запросить настоящий маршрут. Сброс кеша в исследование не входил.

Означает ли 200 у карты, что все страницы работают?

Нет. Карта со снятым товаром вернула 200 и корректно разобралась как XML, но один товар вернул 404. Адреса внутри карты нужно проверять отдельно. Даже странице с 200 на реальном сайте нужны проверки canonical и индексируемости.