Когда данные в CMS или базе уже изменены, а страница Next.js продолжает показывать старую версию, важно определить, какой именно кеш удерживает результат. В App Router одновременно могут участвовать кеш запроса, готового маршрута и клиентского перехода.
Не лечите проблему глобальным force-dynamic без диагностики. Сначала проверьте источник данных и политику fetch, затем серверный Full Route Cache и только после этого Router Cache открытой вкладки. Инвалидация должна быть привязана к событию изменения данных.
Что проверить в первую очередь
Сначала зафиксируйте наблюдаемое поведение и не меняйте сразу несколько настроек. Важны точное время сбоя, адрес или сценарий, ожидаемый результат и последнее известное рабочее состояние. Так можно отличить причину от случайного совпадения и сохранить возможность быстрого отката.
- Сравните прямой запрос к источнику данных и HTML страницы с нового приватного сеанса.
- Уточните, используется App Router или Pages Router и какая версия Next.js развернута.
- Найдите export revalidate, cache/no-store, unstable_cache, revalidatePath и revalidateTag.
- Проверьте, вызывается ли webhook или server action после изменения данных.
Почему возникает проблема
У подобных сбоев редко бывает одна универсальная причина. На итог одновременно влияют конфигурация приложения, окружение, данные, кеш, права и внешние сервисы. Проверка должна идти от внешнего симптома к конкретному уровню, на котором впервые появляется неверное состояние.
- fetch использует Data Cache с большим TTL или тегом, который никогда не инвалидируется.
- Статически отрендеренный маршрут остается в Full Route Cache до следующей регенерации.
- Открытая вкладка показывает Router Cache даже после серверной инвалидации.
- revalidatePath вызывается с неверным путем или без динамического параметра.
- Webhook приходит до фиксации данных, не проходит проверку подписи или завершается ошибкой.
Пошаговая диагностика
Диагностику проводите на копии или в контролируемое время. Перед изменениями сохраните конфигурацию, данные и журналы. Каждый шаг должен отвечать на один вопрос и оставлять измеримый результат: код ответа, запись в логе, состояние процесса, значение поля или воспроизводимый тест.
- Добавьте временную метку источника и сборки, чтобы различать данные API и готовый HTML.
- Откройте URL прямым запросом без client navigation и сравните результат после обновления.
- Проверьте логи обработчика инвалидации, статус ответа и фактические tags/path.
- Посмотрите заголовки CDN и reverse proxy: внешняя прослойка может держать HTML независимо от Next.js.
- Повторите тест после router.refresh и в новой сессии, не используя это как окончательное исправление.
Какие уровни кеша нужно различать
Название revalidate часто используют как общее, хотя обновление разных уровней требует разных действий.
- Data Cache хранит результат серверного fetch или кешированной функции и может инвалидироваться по времени или тегу.
- Full Route Cache хранит результат рендера статического маршрута и зависит от данных, использованных при рендере.
- Router Cache находится в браузере и влияет на клиентские переходы и уже посещенные сегменты.
- CDN или reverse proxy может добавить четвертый независимый уровень с собственным TTL.
- Кеш браузера для статических чанков должен работать по версионированным именам, а не мешать обновлению данных.
Как исправить проблему
Исправление лучше разбить на небольшие обратимые изменения. После каждого шага повторяйте исходный сценарий и проверяйте соседние функции. Если правка касается данных, сначала выполните ее на ограниченной выборке и сохраните журнал затронутых записей.
- Назначьте cache policy каждому источнику: статичный, с TTL, по тегу или no-store.
- После изменения сущности вызывайте revalidateTag для данных или revalidatePath для конкретного маршрута.
- Проверяйте подпись webhook и выполняйте инвалидацию после успешного сохранения данных.
- При server action обновляйте серверный кеш и согласованно обновляйте интерфейс через refresh.
- Настройте CDN так, чтобы он не удерживал персональные или регенерируемые страницы дольше приложения.
Безопасный порядок внедрения
- Сохраните резервную копию затрагиваемых файлов, базы и конфигурации, а также заранее опишите способ отката.
- Воспроизведите сбой на тестовой записи, учетной записи или отдельном окружении без реальных платежей и рассылок.
- Вносите по одному логическому изменению, фиксируя его в системе контроля версий или журнале работ.
- Не отключайте права, проверку входных данных и защитные механизмы только ради исчезновения сообщения об ошибке.
- После выкладки контролируйте логи, метрики и ключевой пользовательский сценарий, а не только открытие одной страницы.
Как проверить результат
Успешный разовый тест еще не доказывает исправление. Нужны повторный запуск, крайние случаи и проверка после очистки кеша, перезапуска процесса или новой сессии. Для критичных сценариев полезно сохранить автоматический тест или хотя бы короткий регрессионный чек-лист.
- После изменения данные появляются в пределах заявленного TTL или сразу после события инвалидации.
- Прямой запрос, переход внутри приложения и новая вкладка показывают одну версию.
- Обновление одной сущности не сбрасывает весь сайт без необходимости.
- Сбой webhook виден в логах и допускает безопасный повтор без потери события.
Типичные ошибки при исправлении
- Добавлять Math.random или Date.now, чтобы случайно сделать маршрут динамическим.
- Отключать весь кеш сайта вместо настройки конкретного источника.
- Путать обновление Router Cache в браузере с серверной инвалидацией данных.
- Вызывать revalidate до коммита базы и снова кешировать старое значение.
Как предотвратить повторение
Профилактика строится вокруг наблюдаемости и воспроизводимости: понятных конфигураций, контролируемых релизов, журналов без секретов и тестов на реальные сценарии. Важно не просто убрать текущий симптом, а сделать следующий похожий сбой заметным раньше пользователя.
- Документируйте кеш-политику рядом с каждым источником данных.
- Пишите интеграционный тест: изменение сущности, инвалидация, запрос страницы.
- Логируйте тип, путь, тег и результат событий revalidate.
- Мониторьте очередь webhooks и расхождение версии данных между API и страницей.
Что подготовить для разбора
- Краткое описание ожидаемого и фактического поведения без паролей, токенов и персональных данных.
- Точное время и последовательность действий, после которых появляется проблема.
- Версии приложения, окружения и зависимостей, а также перечень последних изменений.
- Фрагменты журналов с контекстом до и после ошибки; секреты в них необходимо скрыть.
- Описание уже выполненных проверок и способ безопасно повторить проблему.
Частые вопросы
Поможет ли cache: no-store?
Он исключит Data Cache для конкретного запроса, но увеличит нагрузку и не исправит внешний CDN или клиентское состояние. Используйте его только для действительно динамичных данных.
Чем revalidateTag отличается от revalidatePath?
Тег инвалидирует связанные кешированные данные, а путь — конкретный маршрут. Выбор зависит от того, одна сущность используется на скольких страницах.
Когда нужна помощь специалиста
Если Next.js отдает старые данные и непонятно, где они задерживаются, я могу проследить источник, все уровни кеша и событие обновления, настроить точечную инвалидацию и проверить поведение после релиза.