Инкрементальная статическая регенерация (ISR)

Примеры

Next.js позволяет создавать или обновлять статические страницы после сборки вашего сайта. Инкрементальная статическая регенерация (ISR) позволяет использовать статическую генерацию для отдельных страниц без необходимости пересобирать весь сайт. С ISR вы сохраняете преимущества статики, масштабируясь до миллионов страниц.

Важно знать: В настоящее время edge runtime несовместим с ISR, хотя вы можете использовать stale-while-revalidate, вручную установив заголовок cache-control.

Для использования ISR добавьте свойство revalidate в getStaticProps:

function Blog({ posts }) {
  return (
    <ul>
      {posts.map((post) => (
        <li key={post.id}>{post.title}</li>
      ))}
    </ul>
  )
}

// Эта функция вызывается во время сборки на стороне сервера.
// Она может быть вызвана снова в serverless-функции,
// если включена ревалидация и поступает новый запрос
export async function getStaticProps() {
  const res = await fetch('https://.../posts')
  const posts = await res.json()

  return {
    props: {
      posts,
    },
    // Next.js попытается регенерировать страницу:
    // - При поступлении запроса
    // - Не чаще чем раз в 10 секунд
    revalidate: 10, // В секундах
  }
}

// Эта функция вызывается во время сборки на стороне сервера.
// Она может быть вызвана снова в serverless-функции,
// если путь не был сгенерирован.
export async function getStaticPaths() {
  const res = await fetch('https://.../posts')
  const posts = await res.json()

  // Получаем пути для предварительного рендеринга на основе постов
  const paths = posts.map((post) => ({
    params: { id: post.id },
  }))

  // Предварительно рендерим только эти пути во время сборки.
  // { fallback: 'blocking' } будет рендерить страницы
  // по требованию, если путь не существует.
  return { paths, fallback: 'blocking' }
}

export default Blog

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

  • Все последующие запросы к странице в течение 10 секунд также будут мгновенно возвращать кеш.
  • По истечении 10-секундного интервала следующий запрос всё ещё покажет устаревшую (stale) страницу из кеша.
  • Next.js запустит фоновую регенерацию страницы.
  • После успешной генерации Next.js инвалидирует кеш и покажет обновлённую страницу. Если фоновая регенерация завершится ошибкой, старая страница останется без изменений.

При запросе пути, который не был сгенерирован, Next.js выполнит серверный рендеринг страницы при первом запросе. Последующие запросы будут обслуживать статический файл из кеша. На Vercel ISR сохраняет кеш глобально и обрабатывает откаты.

Важно знать: Проверьте, включено ли кеширование у вашего провайдера данных. Возможно, потребуется отключить его (например, useCdn: false), иначе ревалидация не сможет получить свежие данные для обновления кеша ISR. Кеширование может происходить на CDN (для запрашиваемого эндпоинта), если он возвращает заголовок Cache-Control.

Ревалидация по требованию

Если вы установите revalidate равным 60, все посетители будут видеть одну и ту же сгенерированную версию вашего сайта в течение минуты. Единственный способ инвалидировать кеш — это когда кто-то посетит страницу после истечения минуты.

Начиная с версии v12.2.0, Next.js поддерживает инкрементальную статическую регенерацию по требованию для ручной очистки кеша Next.js для конкретной страницы. Это упрощает обновление сайта в случаях:

  • Создания или обновления контента в вашей headless CMS
  • Изменения метаданных в электронной коммерции (цена, описание, категория, отзывы и т.д.)

В getStaticProps не нужно указывать revalidate для использования ревалидации по требованию. Если revalidate не указан, Next.js будет использовать значение по умолчанию false (без ревалидации) и ревалидировать страницу только по требованию при вызове revalidate().

Важно знать: Middleware не будет выполняться для запросов ISR по требованию. Вместо этого вызывайте revalidate() для точного пути, который нужно ревалидировать. Например, если у вас есть pages/blog/[slug].js и реврайт с /post-1 -> /blog/post-1, вам нужно вызвать res.revalidate('/blog/post-1').

Использование ревалидации по требованию

Сначала создайте секретный токен, известный только вашему приложению Next.js. Этот секрет будет использоваться для предотвращения несанкционированного доступа к API-маршруту ревалидации. Вы можете обратиться к маршруту (вручную или через вебхук) по следующему URL:

Терминал
https://<ваш-сайт.com>/api/revalidate?secret=<токен>

Затем добавьте секрет как переменную окружения в ваше приложение. Наконец, создайте API-маршрут для ревалидации:

pages/api/revalidate.js
export default async function handler(req, res) {
  // Проверяем секрет для подтверждения валидности запроса
  if (req.query.secret !== process.env.MY_SECRET_TOKEN) {
    return res.status(401).json({ message: 'Неверный токен' })
  }

  try {
    // Это должен быть фактический путь, а не реврайт
    // Например, для "/blog/[slug]" это должен быть "/blog/post-1"
    await res.revalidate('/path-to-revalidate')
    return res.json({ revalidated: true })
  } catch (err) {
    // При ошибке Next.js продолжит показывать
    // последнюю успешно сгенерированную страницу
    return res.status(500).send('Ошибка ревалидации')
  }
}

Посмотрите наше демо чтобы увидеть ревалидацию по требованию в действии и оставить отзыв.

Тестирование ISR по требованию во время разработки

При локальном запуске с next dev функция getStaticProps вызывается при каждом запросе. Для проверки правильности конфигурации ISR по требованию вам потребуется создать продакшен-сборку и запустить продакшен-сервер:

Терминал
$ next build
$ next start

Затем вы можете убедиться, что статические страницы успешно ревалидируются.

Обработка ошибок и ревалидация

Если при фоновой регенерации в getStaticProps возникает ошибка или вы вручную выбрасываете ошибку, будет продолжена демонстрация последней успешно сгенерированной страницы. При следующем запросе Next.js повторно вызовет getStaticProps.

export async function getStaticProps() {
  // Если этот запрос выбросит необработанную ошибку, Next.js
  // не инвалидирует текущую страницу и
  // повторит вызов getStaticProps при следующем запросе.
  const res = await fetch('https://.../posts')
  const posts = await res.json()

  if (!res.ok) {
    // При ошибке сервера можно выбросить ошибку,
    // чтобы кеш не обновлялся до следующего успешного запроса.
    throw new Error(`Не удалось получить посты, статус ${res.status}`)
  }

  // При успешном запросе возвращаем посты
  // и ревалидируем каждые 10 секунд.
  return {
    props: {
      posts,
    },
    revalidate: 10,
  }
}

Самостоятельный хостинг ISR

Инкрементальная статическая регенерация (ISR) работает на самостоятельно размещённых Next.js сайтах из коробки при использовании next start.

Узнайте больше о самостоятельном хостинге Next.js.

История версий

ВерсияИзменения
v14.1.0Стабилизирован пользовательский cacheHandler.
v12.2.0ISR по требованию стабилизирован.
v12.1.0Добавлена ISR по требованию (бета).
v12.0.0Добавлен fallback для ISR с учётом ботов.
v9.5.0Добавлен Base Path.