Menu

Inkrementelle Statische Regenerierung (ISR)

Beispiele

Mit Inkrementeller Statischer Regenerierung (ISR) kannst du:

  • Statische Inhalte aktualisieren, ohne die gesamte Website neu zu erstellen
  • Die Serverlast reduzieren, indem vorgerenderte, statische Seiten für die meisten Anfragen bereitgestellt werden
  • Sicherstellen, dass korrekte cache-control Header automatisch zu den Seiten hinzugefügt werden
  • Große Mengen an Inhaltsseiten verwalten, ohne lange next build Zeiten

Hier ist ein minimales Beispiel:

pages/blog/[id].tsx
TypeScript
import type { GetStaticPaths, GetStaticProps } from 'next'
 
interface Post {
  id: string
  title: string
  content: string
}
 
interface Props {
  post: Post
}
 
export const getStaticPaths: GetStaticPaths = async () => {
  const posts = await fetch('https://api.vercel.app/blog').then((res) =>
    res.json()
  )
  const paths = posts.map((post: Post) => ({
    params: { id: String(post.id) },
  }))
 
  // Wir werden nur diese Pfade zur Build-Zeit vorrendern.
  // { fallback: 'blocking' } wird Seiten server-seitig
  // bei Bedarf rendern, wenn der Pfad nicht existiert.
  return { paths, fallback: false }
}
 
export const getStaticProps: GetStaticProps<Props> = async ({
  params,
}: {
  params: { id: string }
}) => {
  const post = await fetch(`https://api.vercel.app/blog/${params.id}`).then(
    (res) => res.json()
  )
 
  return {
    props: { post },
    // Next.js wird den Cache invalidieren, wenn eine
    // Anfrage eingeht, höchstens alle 60 Sekunden.
    revalidate: 60,
  }
}
 
export default function Page({ post }: Props) {
  return (
    <main>
      <h1>{post.title}</h1>
      <p>{post.content}</p>
    </main>
  )
}

So funktioniert dieses Beispiel:

  1. Während next build werden alle bekannten Blogbeiträge generiert (in diesem Beispiel sind es 25)
  2. Alle Anfragen an diese Seiten (z.B. /blog/1) werden gecached und sind sofort verfügbar
  3. Nach Ablauf von 60 Sekunden zeigt die nächste Anfrage weiterhin die gecachte (veraltete) Seite
  4. Der Cache wird invalidiert und eine neue Version der Seite wird im Hintergrund generiert
  5. Nach erfolgreicher Generierung zeigt Next.js die aktualisierte Seite und speichert sie im Cache
  6. Wenn /blog/26 angefragt wird, generiert Next.js diese Seite bei Bedarf und speichert sie im Cache

Referenz

Funktionen

Beispiele

On-Demand Validierung mit res.revalidate()

Für eine präzisere Revalidierungsmethode kannst du res.revalidate verwenden, um eine neue Seite bei Bedarf von einer API Route aus zu generieren.

Diese API Route kann zum Beispiel unter /api/revalidate?secret=<token> aufgerufen werden, um einen bestimmten Blogbeitrag zu revalidieren. Erstelle einen geheimen Token, der nur deiner Next.js App bekannt ist. Dieser Token wird verwendet, um unberechtigten Zugriff auf die Revalidierungs-API-Route zu verhindern.

pages/api/revalidate.ts
import type { NextApiRequest, NextApiResponse } from 'next'
 
export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse
) {
  // Prüfen des Tokens zur Bestätigung einer gültigen Anfrage
  if (req.query.secret !== process.env.MY_SECRET_TOKEN) {
    return res.status(401).json({ message: 'Ungültiger Token' })
  }
 
  try {
    // Dies sollte der tatsächliche Pfad sein, nicht ein umgeschriebener Pfad
    // z.B. für "/posts/[id]" sollte dies "/posts/1" sein
    await res.revalidate('/posts/1')
    return res.json({ revalidated: true })
  } catch (err) {
    // Wenn ein Fehler auftritt, wird Next.js weiterhin
    // die zuletzt erfolgreich generierte Seite anzeigen
    return res.status(500).send('Fehler bei der Revalidierung')
  }
}
pages/api/revalidate.js
export default async function handler(req, res) {
  // Prüfen des Tokens zur Bestätigung einer gültigen Anfrage
  if (req.query.secret !== process.env.MY_SECRET_TOKEN) {
    return res.status(401).json({ message: 'Ungültiger Token' })
  }
 
  try {
    // Dies sollte der tatsächliche Pfad sein, nicht ein umgeschriebener Pfad
    // z.B. für "/posts/[id]" sollte dies "/posts/1" sein
    await res.revalidate('/posts/1')
    return res.json({ revalidated: true })
  } catch (err) {
    // Wenn ein Fehler auftritt, wird Next.js weiterhin
    // die zuletzt erfolgreich generierte Seite anzeigen
    return res.status(500).send('Fehler bei der Revalidierung')
  }
}

Wenn du On-Demand Revalidierung verwendest, musst du keine revalidate Zeit innerhalb von getStaticProps angeben. Next.js wird den Standardwert false (keine Revalidierung) verwenden und die Seite nur bei Bedarf revalidieren, wenn res.revalidate() aufgerufen wird.

Umgang mit nicht abgefangenen Ausnahmen

Wenn es einen Fehler innerhalb von getStaticProps bei der Hintergrund-Regeneration gibt oder du manuell einen Fehler wirfst, wird die zuletzt erfolgreich generierte Seite weiterhin angezeigt. Bei der nächsten Anfrage wird Next.js erneut versuchen, getStaticProps aufzurufen.

pages/blog/[id].tsx
TypeScript
import type { GetStaticProps } from 'next'
 
interface Post {
  id: string
  title: string
  content: string
}
 
interface Props {
  post: Post
}
 
export const getStaticProps: GetStaticProps<Props> = async ({
  params,
}: {
  params: { id: string }
}) => {
  // Wenn diese Anfrage einen nicht abgefangenen Fehler wirft, wird Next.js
  // die aktuell angezeigte Seite nicht invalidieren und
  // getStaticProps bei der nächsten Anfrage erneut versuchen.
  const res = await fetch(`https://api.vercel.app/blog/${params.id}`)
  const post: Post = await res.json()
 
  if (!res.ok) {
    // Bei einem Serverfehler möchtest du vielleicht
    // einen Fehler werfen anstatt zurückzugeben, damit der Cache nicht aktualisiert wird
    // bis zur nächsten erfolgreichen Anfrage.
    throw new Error(`Fehler beim Abrufen der Beiträge, Status ${res.status}`)
  }
 
  return {
    props: { post },
    // Next.js wird den Cache invalidieren, wenn eine
    // Anfrage eingeht, höchstens alle 60 Sekunden.
    revalidate: 60,
  }
}

Anpassen des Cache-Speicherorts

Caching und Revalidierung von Seiten (mit Inkrementeller Statischer Regenerierung) verwenden denselben gemeinsamen Cache. Bei Deployment auf Vercel wird der ISR-Cache automatisch in dauerhaftem Speicher persistiert.

Bei Self-Hosting wird der ISR-Cache im Dateisystem (auf der Festplatte) deines Next.js-Servers gespeichert. Dies funktioniert automatisch beim Self-Hosting sowohl mit dem Pages als auch dem App Router.

Du kannst den Next.js Cache-Speicherort konfigurieren, wenn du gecachte Seiten und Daten in dauerhaftem Speicher persistieren oder den Cache über mehrere Container oder Instanzen deiner Next.js Anwendung hinweg teilen möchtest. Mehr erfahren.

Fehlerbehebung

Debugging von Cache-Daten in lokaler Entwicklung

Wenn du die fetch API verwendest, kannst du zusätzliches Logging hinzufügen, um zu verstehen, welche Anfragen gecached oder nicht gecached sind. Mehr über die logging Option.

next.config.js
module.exports = {
  logging: {
    fetches: {
      fullUrl: true,
    },
  },
}

Überprüfen des korrekten Produktionsverhaltens

Um zu überprüfen, ob deine Seiten im Produktionsmodus korrekt gecached und revalidiert werden, kannst du lokal testen, indem du next build und dann next start ausführst, um den Next.js Produktionsserver zu starten.

Dies ermöglicht es dir, das ISR-Verhalten so zu testen, wie es in einer Produktionsumgebung funktionieren würde. Für weitere Debugging-Möglichkeiten füge die folgende Umgebungsvariable zu deiner .env Datei hinzu:

.env
NEXT_PRIVATE_DEBUG_CACHE=1

Dies wird den Next.js Server dazu veranlassen, ISR Cache-Treffer und -Fehltreffer in der Konsole zu protokollieren. Du kannst die Ausgabe überprüfen, um zu sehen, welche Seiten während next build generiert werden, sowie wie Seiten aktualisiert werden, wenn Pfade bei Bedarf aufgerufen werden.

Einschränkungen

  • ISR wird nur bei Verwendung der Node.js Runtime (Standard) unterstützt.
  • ISR wird nicht beim Erstellen eines Statischen Exports unterstützt.
  • Middleware wird nicht für On-Demand ISR-Anfragen ausgeführt, das bedeutet, dass Pfadumschreibungen oder Logik in Middleware nicht angewendet werden. Stelle sicher, dass du den exakten Pfad revalidierst. Zum Beispiel /post/1 anstelle eines umgeschriebenen /post-1.

Versionshistorie

VersionÄnderungen
v14.1.0Custom cacheHandler ist stabil.
v13.0.0App Router wird eingeführt.
v12.2.0Pages Router: On-Demand ISR ist stabil
v12.0.0Pages Router: Bot-bewusster ISR Fallback hinzugefügt.
v9.5.0Pages Router: Stabiles ISR eingeführt.