Weiterleitungen

Es gibt mehrere Möglichkeiten, Weiterleitungen in Next.js zu handhaben. Diese Seite stellt jede verfügbare Option vor, erläutert Anwendungsfälle und zeigt, wie Sie eine große Anzahl von Weiterleitungen verwalten können.

APIZweckVerwendungsortStatuscode
redirectBenutzer nach Mutation oder Ereignis umleitenServer Components, Server Actions, Route Handlers307 (Temporär) oder 303 (Server Action)
permanentRedirectBenutzer dauerhaft umleitenServer Components, Server Actions, Route Handlers308 (Permanent)
useRouterClient-seitige Navigation durchführenEvent Handler in Client ComponentsN/A
redirects in next.config.jsAnfrage basierend auf Pfad umleitennext.config.js Datei307 (Temporär) oder 308 (Permanent)
NextResponse.redirectAnfrage basierend auf Bedingung umleitenMiddlewareBeliebig

redirect-Funktion

Die redirect-Funktion ermöglicht es, Benutzer auf eine andere URL umzuleiten. Sie können redirect in Server Components, Route Handlers und Server Actions aufrufen.

redirect wird häufig nach einer Mutation oder einem Ereignis verwendet. Zum Beispiel beim Erstellen eines Posts:

'use server'

import { redirect } from 'next/navigation'
import { revalidatePath } from 'next/cache'

export async function createPost(id: string) {
  try {
    // Datenbank aufrufen
  } catch (error) {
    // Fehler behandeln
  }

  revalidatePath('/posts') // Cache aktualisieren
  redirect(`/post/${id}`) // Zur neuen Post-Seite navigieren
}
'use server'

import { redirect } from 'next/navigation'
import { revalidatePath } from 'next/cache'

export async function createPost(id) {
  try {
    // Datenbank aufrufen
  } catch (error) {
    // Fehler behandeln
  }

  revalidatePath('/posts') // Cache aktualisieren
  redirect(`/post/${id}`) // Zur neuen Post-Seite navigieren
}

Gut zu wissen:

  • redirect gibt standardmäßig einen 307 (Temporary Redirect) Statuscode zurück. Bei Verwendung in einer Server Action wird ein 303 (See Other) zurückgegeben, der häufig für Weiterleitungen nach POST-Anfragen verwendet wird.
  • redirect wirft intern einen Fehler und sollte daher außerhalb von try/catch-Blöcken aufgerufen werden.
  • redirect kann in Client Components während des Rendering-Prozesses aufgerufen werden, aber nicht in Event Handlern. Verwenden Sie stattdessen den useRouter-Hook.
  • redirect akzeptiert auch absolute URLs und kann für externe Links verwendet werden.
  • Für Weiterleitungen vor dem Rendering-Prozess verwenden Sie next.config.js oder Middleware.

Weitere Informationen finden Sie in der redirect-API-Referenz.

permanentRedirect-Funktion

Die permanentRedirect-Funktion ermöglicht es, Benutzer dauerhaft auf eine andere URL umzuleiten. Sie können permanentRedirect in Server Components, Route Handlers und Server Actions aufrufen.

permanentRedirect wird häufig nach Mutationen verwendet, die die kanonische URL einer Entität ändern, z.B. beim Aktualisieren eines Profil-URLs nach einer Namensänderung:

'use server'

import { permanentRedirect } from 'next/navigation'
import { revalidateTag } from 'next/cache'

export async function updateUsername(username: string, formData: FormData) {
  try {
    // Datenbank aufrufen
  } catch (error) {
    // Fehler behandeln
  }

  revalidateTag('username') // Referenzen aktualisieren
  permanentRedirect(`/profile/${username}`) // Zum neuen Profil navigieren
}
'use server'

import { permanentRedirect } from 'next/navigation'
import { revalidateTag } from 'next/cache'

export async function updateUsername(username, formData) {
  try {
    // Datenbank aufrufen
  } catch (error) {
    // Fehler behandeln
  }

  revalidateTag('username') // Referenzen aktualisieren
  permanentRedirect(`/profile/${username}`) // Zum neuen Profil navigieren
}

Gut zu wissen:

  • permanentRedirect gibt standardmäßig einen 308 (Permanent Redirect) Statuscode zurück.
  • permanentRedirect akzeptiert auch absolute URLs und kann für externe Links verwendet werden.
  • Für Weiterleitungen vor dem Rendering-Prozess verwenden Sie next.config.js oder Middleware.

Weitere Informationen finden Sie in der permanentRedirect-API-Referenz.

useRouter()-Hook

Für Weiterleitungen in Event Handlern von Client Components können Sie die push-Methode des useRouter-Hooks verwenden. Beispiel:

'use client'

import { useRouter } from 'next/navigation'

export default function Page() {
  const router = useRouter()

  return (
    <button type="button" onClick={() => router.push('/dashboard')}>
      Dashboard
    </button>
  )
}
'use client'

import { useRouter } from 'next/navigation'

export default function Page() {
  const router = useRouter()

  return (
    <button type="button" onClick={() => router.push('/dashboard')}>
      Dashboard
    </button>
  )
}

Gut zu wissen:

  • Für nicht-programmatische Navigation sollten Sie eine <Link>-Komponente verwenden.

Weitere Informationen finden Sie in der useRouter-API-Referenz.

redirects in next.config.js

Die redirects-Option in der next.config.js-Datei ermöglicht es, eingehende Anfragen basierend auf dem Pfad umzuleiten. Dies ist nützlich bei Änderungen der URL-Struktur oder bei bekannten Weiterleitungen.

redirects unterstützt Pfad, Header-, Cookie- und Query-Matching für flexible Weiterleitungsregeln.

So verwenden Sie redirects:

next.config.js
module.exports = {
  async redirects() {
    return [
      // Einfache Weiterleitung
      {
        source: '/about',
        destination: '/',
        permanent: true,
      },
      // Wildcard-Pfad-Matching
      {
        source: '/blog/:slug',
        destination: '/news/:slug',
        permanent: true,
      },
    ]
  },
}

Weitere Informationen finden Sie in der redirects-API-Referenz.

Gut zu wissen:

  • redirects kann 307 (Temporary Redirect) oder 308 (Permanent Redirect) Statuscodes zurückgeben.
  • Auf einigen Plattformen gibt es Limits (z.B. 1.024 Weiterleitungen auf Vercel). Für große Mengen (1000+) sollten Sie Middleware verwenden. Siehe Weiterleitungen im großen Stil.
  • redirects wird vor Middleware ausgeführt.

NextResponse.redirect in Middleware

Middleware ermöglicht Code-Ausführung vor Abschluss einer Anfrage. Mit NextResponse.redirect können Sie basierend auf der Anfrage umleiten, z.B. für Authentifizierung oder Session-Management.

Beispiel für Authentifizierungs-Weiterleitung:

import { NextResponse, NextRequest } from 'next/server'
import { authenticate } from 'auth-provider'

export function middleware(request: NextRequest) {
  const isAuthenticated = authenticate(request)

  if (isAuthenticated) {
    return NextResponse.next()
  }

  return NextResponse.redirect(new URL('/login', request.url))
}

export const config = {
  matcher: '/dashboard/:path*',
}
import { NextResponse } from 'next/server'
import { authenticate } from 'auth-provider'

export function middleware(request) {
  const isAuthenticated = authenticate(request)

  if (isAuthenticated) {
    return NextResponse.next()
  }

  return NextResponse.redirect(new URL('/login', request.url))
}

export const config = {
  matcher: '/dashboard/:path*',
}

Gut zu wissen:

  • Middleware wird nach redirects in next.config.js und vor dem Rendering ausgeführt.

Weitere Informationen finden Sie in der Middleware-Dokumentation.

Weiterleitungen im großen Stil (Fortgeschritten)

Für große Mengen an Weiterleitungen (1000+) können Sie eine benutzerdefinierte Middleware-Lösung erstellen, ohne die Anwendung neu zu deployen.

Dafür benötigen Sie:

  1. Eine Weiterleitungs-Map
  2. Optimierte Datenabfrage

Next.js-Beispiel: Siehe unser Middleware mit Bloom-Filter-Beispiel für eine Implementierung.

1. Erstellen und Speichern einer Weiterleitungs-Map

Eine Weiterleitungs-Map ist eine Liste von Weiterleitungen, die in einer Datenbank oder JSON-Datei gespeichert werden kann.

Beispiel-Datenstruktur:

{
  "/old": {
    "destination": "/new",
    "permanent": true
  },
  "/blog/post-old": {
    "destination": "/blog/post-new",
    "permanent": true
  }
}

In Middleware können Sie aus Datenbanken wie Vercels Edge Config oder Redis lesen:

import { NextResponse, NextRequest } from 'next/server'
import { get } from '@vercel/edge-config'

type RedirectEntry = {
  destination: string
  permanent: boolean
}

export async function middleware(request: NextRequest) {
  const pathname = request.nextUrl.pathname
  const redirectData = await get(pathname)

  if (redirectData && typeof redirectData === 'string') {
    const redirectEntry: RedirectEntry = JSON.parse(redirectData)
    const statusCode = redirectEntry.permanent ? 308 : 307
    return NextResponse.redirect(redirectEntry.destination, statusCode)
  }

  return NextResponse.next()
}
import { NextResponse } from 'next/server'
import { get } from '@vercel/edge-config'

export async function middleware(request) {
  const pathname = request.nextUrl.pathname
  const redirectData = await get(pathname)

  if (redirectData) {
    const redirectEntry = JSON.parse(redirectData)
    const statusCode = redirectEntry.permanent ? 308 : 307
    return NextResponse.redirect(redirectEntry.destination, statusCode)
  }

  return NextResponse.next()
}

2. Optimierung der Datenabfrageleistung

Das Lesen eines großen Datensatzes für jede eingehende Anfrage kann langsam und ressourcenintensiv sein. Es gibt zwei Möglichkeiten, die Leistung bei der Datenabfrage zu optimieren:

  • Verwenden Sie eine Datenbank, die für schnelle Lesevorgänge optimiert ist, wie z.B. Vercel Edge Config oder Redis.
  • Verwenden Sie eine Datenabfragestrategie wie einen Bloom-Filter, um effizient zu prüfen, ob eine Weiterleitung existiert, bevor die größere Weiterleitungsdatei oder Datenbank gelesen wird.

Bezogen auf das vorherige Beispiel können Sie eine generierte Bloom-Filter-Datei in die Middleware importieren und dann prüfen, ob der Pfad der eingehenden Anfrage im Bloom-Filter enthalten ist.

Falls ja, leiten Sie die Anfrage an einen Route Handler weiter, der die eigentliche Datei überprüft und den Benutzer zur entsprechenden URL weiterleitet. Dadurch wird vermieden, eine große Weiterleitungsdatei in die Middleware zu importieren, was jede eingehende Anfrage verlangsamen könnte.

import { NextResponse, NextRequest } from 'next/server'
import { ScalableBloomFilter } from 'bloom-filters'
import GeneratedBloomFilter from './redirects/bloom-filter.json'

type RedirectEntry = {
  destination: string
  permanent: boolean
}

// Initialisiere Bloom-Filter aus einer generierten JSON-Datei
const bloomFilter = ScalableBloomFilter.fromJSON(GeneratedBloomFilter as any)

export async function middleware(request: NextRequest) {
  // Hole den Pfad der eingehenden Anfrage
  const pathname = request.nextUrl.pathname

  // Prüfe, ob der Pfad im Bloom-Filter enthalten ist
  if (bloomFilter.has(pathname)) {
    // Leite den Pfad an den Route Handler weiter
    const api = new URL(
      `/api/redirects?pathname=${encodeURIComponent(request.nextUrl.pathname)}`,
      request.nextUrl.origin
    )

    try {
      // Hole Weiterleitungsdaten vom Route Handler
      const redirectData = await fetch(api)

      if (redirectData.ok) {
        const redirectEntry: RedirectEntry | undefined =
          await redirectData.json()

        if (redirectEntry) {
          // Bestimme den Statuscode
          const statusCode = redirectEntry.permanent ? 308 : 307

          // Leite zur Ziel-URL weiter
          return NextResponse.redirect(redirectEntry.destination, statusCode)
        }
      }
    } catch (error) {
      console.error(error)
    }
  }

  // Keine Weiterleitung gefunden, Anfrage ohne Weiterleitung fortsetzen
  return NextResponse.next()
}
import { NextResponse } from 'next/server'
import { ScalableBloomFilter } from 'bloom-filters'
import GeneratedBloomFilter from './redirects/bloom-filter.json'

// Initialisiere Bloom-Filter aus einer generierten JSON-Datei
const bloomFilter = ScalableBloomFilter.fromJSON(GeneratedBloomFilter)

export async function middleware(request) {
  // Hole den Pfad der eingehenden Anfrage
  const pathname = request.nextUrl.pathname

  // Prüfe, ob der Pfad im Bloom-Filter enthalten ist
  if (bloomFilter.has(pathname)) {
    // Leite den Pfad an den Route Handler weiter
    const api = new URL(
      `/api/redirects?pathname=${encodeURIComponent(request.nextUrl.pathname)}`,
      request.nextUrl.origin
    )

    try {
      // Hole Weiterleitungsdaten vom Route Handler
      const redirectData = await fetch(api)

      if (redirectData.ok) {
        const redirectEntry = await redirectData.json()

        if (redirectEntry) {
          // Bestimme den Statuscode
          const statusCode = redirectEntry.permanent ? 308 : 307

          // Leite zur Ziel-URL weiter
          return NextResponse.redirect(redirectEntry.destination, statusCode)
        }
      }
    } catch (error) {
      console.error(error)
    }
  }

  // Keine Weiterleitung gefunden, Anfrage ohne Weiterleitung fortsetzen
  return NextResponse.next()
}

Dann im Route Handler:

import { NextRequest, NextResponse } from 'next/server'
import redirects from '@/app/redirects/redirects.json'

type RedirectEntry = {
  destination: string
  permanent: boolean
}

export function GET(request: NextRequest) {
  const pathname = request.nextUrl.searchParams.get('pathname')
  if (!pathname) {
    return new Response('Bad Request', { status: 400 })
  }

  // Hole den Weiterleitungseintrag aus der redirects.json-Datei
  const redirect = (redirects as Record<string, RedirectEntry>)[pathname]

  // Berücksichtige falsch positive Ergebnisse des Bloom-Filters
  if (!redirect) {
    return new Response('No redirect', { status: 400 })
  }

  // Gib den Weiterleitungseintrag zurück
  return NextResponse.json(redirect)
}
import { NextResponse } from 'next/server'
import redirects from '@/app/redirects/redirects.json'

export function GET(request) {
  const pathname = request.nextUrl.searchParams.get('pathname')
  if (!pathname) {
    return new Response('Bad Request', { status: 400 })
  }

  // Hole den Weiterleitungseintrag aus der redirects.json-Datei
  const redirect = redirects[pathname]

  // Berücksichtige falsch positive Ergebnisse des Bloom-Filters
  if (!redirect) {
    return new Response('No redirect', { status: 400 })
  }

  // Gib den Weiterleitungseintrag zurück
  return NextResponse.json(redirect)
}

Gut zu wissen:

  • Um einen Bloom-Filter zu generieren, können Sie eine Bibliothek wie bloom-filters verwenden.
  • Sie sollten Anfragen an Ihren Route Handler validieren, um bösartige Anfragen zu verhindern.