Инкрементальная статическая регенерация (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-секундного интервала следующий запрос всё равно покажет кэшированную (устаревшую) страницу.
- 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
- Изменения метаданных в ecommerce (цена, описание, категория, отзывы и т. д.)
Внутри getStaticProps
вам не нужно указывать revalidate
для использования ревалидации по запросу. Если revalidate
опущен, Next.js будет использовать значение по умолчанию false
(без ревалидации) и ревалидировать страницу только по запросу при вызове revalidate()
.
Важно знать: Middleware не будет выполняться для запросов On-Demand ISR. Вместо этого вызывайте
revalidate()
для точного пути, который нужно ревалидировать. Например, если у вас естьpages/blog/[slug].js
и rewrite с/post-1
->/blog/post-1
, вам нужно вызватьres.revalidate('/blog/post-1')
.
Использование ревалидации по запросу
Сначала создайте секретный токен, известный только вашему приложению Next.js. Этот секрет будет использоваться для предотвращения несанкционированного доступа к API-маршруту ревалидации. Вы можете обратиться к маршруту (вручную или через вебхук) по следующему URL:
https://<your-site.com>/api/revalidate?secret=<token>
Затем добавьте секрет как переменную окружения в ваше приложение. Наконец, создайте API-маршрут для ревалидации:
export default async function handler(req, res) {
// Проверяем секрет для подтверждения валидности запроса
if (req.query.secret !== process.env.MY_SECRET_TOKEN) {
return res.status(401).json({ message: 'Неверный токен' })
}
try {
// Это должен быть фактический путь, а не rewritten
// Например, для "/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('Ошибка ревалидации')
}
}
Посмотрите наше демо для примера работы ревалидации по запросу и оставьте отзыв.
Тестирование On-Demand ISR во время разработки
При локальном запуске с next dev
функция getStaticProps
вызывается при каждом запросе. Чтобы проверить корректность конфигурации On-Demand 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
.
Этот подход можно использовать при развёртывании в оркестраторах контейнеров, таких как Kubernetes или HashiCorp Nomad. По умолчанию сгенерированные ресурсы хранятся в памяти каждого pod. Это означает, что каждый pod будет иметь свою копию статических файлов. Устаревшие данные могут отображаться до тех пор, пока не будет получен запрос к конкретному pod.
Для обеспечения согласованности между всеми pod можно отключить кэширование в памяти. Это укажет серверу Next.js использовать только ресурсы, сгенерированные ISR в файловой системе.
Вы можете использовать общую сетевую точку монтирования в ваших Kubernetes pod (или аналогичную настройку) для повторного использования одного и того же кэша файловой системы между разными контейнерами. При совместном использовании одной точки монтирования папка .next
, содержащая кэш next/image
, также будет общей.
Чтобы отключить кэширование в памяти, установите isrMemoryCacheSize
в 0
в файле next.config.js
:
module.exports = {
experimental: {
// По умолчанию 50MB
isrMemoryCacheSize: 0, // размер кэша в байтах
},
}
Важно знать: В зависимости от конфигурации общей точки монтирования может потребоваться учитывать состояние гонки между несколькими pod, пытающимися обновить кэш одновременно.
История версий
Версия | Изменения |
---|---|
v12.2.0 | On-Demand ISR стабилен |
v12.1.0 | Добавлен On-Demand ISR (бета). |
v12.0.0 | Добавлен Bot-aware ISR fallback. |
v9.5.0 | Добавлен Base Path. |
getServerSideProps
Получение данных при каждом запросе с помощью `getServerSideProps`.
Получение данных на стороне клиента (Client-side Fetching)
Узнайте о получении данных на стороне клиента и использовании библиотеки SWR — хука React для получения данных, который обрабатывает кэширование, ревалидацию, отслеживание фокуса, повторные запросы с интервалами и многое другое.