Middleware

Middleware ermöglicht es Ihnen, Code auszuführen, bevor eine Anfrage abgeschlossen ist. Basierend auf der eingehenden Anfrage können Sie dann die Antwort durch Umschreiben, Weiterleiten, Modifizieren der Anfrage- oder Antwort-Header oder direktes Antworten anpassen.

Middleware wird ausgeführt, bevor zwischengespeicherte Inhalte und Routen abgeglichen werden. Weitere Details finden Sie unter Pfade abgleichen.

Anwendungsfälle

Einige gängige Szenarien, in denen Middleware effektiv ist, umfassen:

  • Schnelle Weiterleitungen nach dem Lesen von Teilen der eingehenden Anfrage
  • Umschreiben auf verschiedene Seiten basierend auf A/B-Tests oder Experimenten
  • Modifizieren von Headern für alle Seiten oder eine Teilmenge von Seiten

Middleware ist nicht geeignet für:

  • Langsame Datenabfragen
  • Sitzungsverwaltung

Konvention

Verwenden Sie die Datei middleware.ts (oder .js) im Stammverzeichnis Ihres Projekts, um Middleware zu definieren. Beispielsweise auf derselben Ebene wie pages oder app, oder innerhalb von src, falls zutreffend.

Hinweis: Obwohl nur eine middleware.ts-Datei pro Projekt unterstützt wird, können Sie Ihre Middleware-Logik dennoch modular organisieren. Unterteilen Sie Middleware-Funktionalitäten in separate .ts- oder .js-Dateien und importieren Sie sie in Ihre Haupt-middleware.ts-Datei. Dies ermöglicht eine übersichtlichere Verwaltung von routenspezifischer Middleware, die in der middleware.ts für zentrale Kontrolle zusammengefasst wird. Durch die Durchsetzung einer einzigen Middleware-Datei wird die Konfiguration vereinfacht, potenzielle Konflikte vermieden und die Leistung durch die Vermeidung mehrerer Middleware-Schichten optimiert.

Beispiel

import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

// Diese Funktion kann als `async` markiert werden, wenn `await` im Inneren verwendet wird
export function middleware(request: NextRequest) {
  return NextResponse.redirect(new URL('/home', request.url))
}

// Siehe "Pfade abgleichen" unten, um mehr zu erfahren
export const config = {
  matcher: '/about/:path*',
}

Pfade abgleichen

Middleware wird für jede Route in Ihrem Projekt aufgerufen. Angesichts dessen ist es entscheidend, Matcher zu verwenden, um bestimmte Routen gezielt anzusprechen oder auszuschließen. Die folgende Ausführungsreihenfolge gilt:

  1. headers aus next.config.js
  2. redirects aus next.config.js
  3. Middleware (rewrites, redirects, etc.)
  4. beforeFiles (rewrites) aus next.config.js
  5. Dateisystemrouten (public/, _next/static/, pages/, app/, etc.)
  6. afterFiles (rewrites) aus next.config.js
  7. Dynamische Routen (/blog/[slug])
  8. fallback (rewrites) aus next.config.js

Es gibt zwei Möglichkeiten zu definieren, auf welchen Pfaden Middleware ausgeführt wird:

  1. Benutzerdefinierte Matcher-Konfiguration
  2. Bedingte Anweisungen

Matcher

matcher ermöglicht es Ihnen, Middleware auf bestimmte Pfade zu filtern.

middleware.js
export const config = {
  matcher: '/about/:path*',
}

Sie können einen einzelnen Pfad oder mehrere Pfade mit einer Array-Syntax abgleichen:

middleware.js
export const config = {
  matcher: ['/about/:path*', '/dashboard/:path*'],
}

Die matcher-Konfiguration erlaubt vollständige Regex, sodass Abgleiche wie negative Lookaheads oder Zeichenabgleiche unterstützt werden. Ein Beispiel für einen negativen Lookahead, um alle Pfade außer bestimmten abzugleichen, ist hier zu sehen:

middleware.js
export const config = {
  matcher: [
    /*
     * Alle Anfragepfade abgleichen, außer denen, die mit folgenden beginnen:
     * - api (API-Routen)
     * - _next/static (statische Dateien)
     * - _next/image (Bildoptimierungsdateien)
     * - favicon.ico, sitemap.xml, robots.txt (Metadaten-Dateien)
     */
    '/((?!api|_next/static|_next/image|favicon.ico|sitemap.xml|robots.txt).*)',
  ],
}

Sie können Middleware für bestimmte Anfragen auch umgehen, indem Sie die missing- oder has-Arrays oder eine Kombination aus beiden verwenden:

middleware.js
export const config = {
  matcher: [
    /*
     * Alle Anfragepfade abgleichen, außer denen, die mit folgenden beginnen:
     * - api (API-Routen)
     * - _next/static (statische Dateien)
     * - _next/image (Bildoptimierungsdateien)
     * - favicon.ico, sitemap.xml, robots.txt (Metadaten-Dateien)
     */
    {
      source:
        '/((?!api|_next/static|_next/image|favicon.ico|sitemap.xml|robots.txt).*)',
      missing: [
        { type: 'header', key: 'next-router-prefetch' },
        { type: 'header', key: 'purpose', value: 'prefetch' },
      ],
    },

    {
      source:
        '/((?!api|_next/static|_next/image|favicon.ico|sitemap.xml|robots.txt).*)',
      has: [
        { type: 'header', key: 'next-router-prefetch' },
        { type: 'header', key: 'purpose', value: 'prefetch' },
      ],
    },

    {
      source:
        '/((?!api|_next/static|_next/image|favicon.ico|sitemap.xml|robots.txt).*)',
      has: [{ type: 'header', key: 'x-present' }],
      missing: [{ type: 'header', key: 'x-missing', value: 'prefetch' }],
    },
  ],
}

Gut zu wissen: Die matcher-Werte müssen Konstanten sein, damit sie zur Build-Zeit statisch analysiert werden können. Dynamische Werte wie Variablen werden ignoriert.

Konfigurierte Matcher:

  1. MÜSSEN mit / beginnen
  2. Können benannte Parameter enthalten: /about/:path passt auf /about/a und /about/b, aber nicht auf /about/a/c
  3. Können Modifikatoren für benannte Parameter haben (beginnend mit :): /about/:path* passt auf /about/a/b/c, weil * null oder mehr bedeutet. ? bedeutet null oder eins und + eins oder mehr
  4. Können reguläre Ausdrücke in Klammern verwenden: /about/(.*) ist dasselbe wie /about/:path*

Weitere Details finden Sie in der path-to-regexp-Dokumentation.

Gut zu wissen: Aus Gründen der Abwärtskompatibilität betrachtet Next.js /public immer als /public/index. Daher passt ein Matcher von /public/:path darauf.

Bedingte Anweisungen

import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

export function middleware(request: NextRequest) {
  if (request.nextUrl.pathname.startsWith('/about')) {
    return NextResponse.rewrite(new URL('/about-2', request.url))
  }

  if (request.nextUrl.pathname.startsWith('/dashboard')) {
    return NextResponse.rewrite(new URL('/dashboard/user', request.url))
  }
}

NextResponse

Die NextResponse-API ermöglicht es Ihnen:

  • Die eingehende Anfrage auf eine andere URL umzuleiten (redirect)
  • Die Antwort durch Anzeigen einer bestimmten URL umzuschreiben (rewrite)
  • Anfrage-Header für API-Routen, getServerSideProps und rewrite-Ziele zu setzen
  • Antwort-Cookies zu setzen
  • Antwort-Header zu setzen

Um eine Antwort aus der Middleware zu erzeugen, können Sie:

  1. Auf eine Route (Page oder Route Handler) umschreiben, die eine Antwort erzeugt
  2. Direkt eine NextResponse zurückgeben. Siehe Antwort erzeugen

Cookies verwenden

Cookies sind reguläre Header. Bei einer Request werden sie im Cookie-Header gespeichert. Bei einer Response befinden sie sich im Set-Cookie-Header. Next.js bietet eine bequeme Möglichkeit, auf diese Cookies zuzugreifen und sie zu manipulieren, über die cookies-Erweiterung von NextRequest und NextResponse.

  1. Für eingehende Anfragen bietet cookies folgende Methoden: get, getAll, set und delete Cookies. Sie können das Vorhandensein eines Cookies mit has überprüfen oder alle Cookies mit clear entfernen.
  2. Für ausgehende Antworten bietet cookies folgende Methoden: get, getAll, set und delete.
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

export function middleware(request: NextRequest) {
  // Angenommen, ein "Cookie:nextjs=fast"-Header ist in der eingehenden Anfrage vorhanden
  // Cookies aus der Anfrage mit der `RequestCookies`-API abrufen
  let cookie = request.cookies.get('nextjs')
  console.log(cookie) // => { name: 'nextjs', value: 'fast', Path: '/' }
  const allCookies = request.cookies.getAll()
  console.log(allCookies) // => [{ name: 'nextjs', value: 'fast' }]

  request.cookies.has('nextjs') // => true
  request.cookies.delete('nextjs')
  request.cookies.has('nextjs') // => false

  // Cookies in der Antwort mit der `ResponseCookies`-API setzen
  const response = NextResponse.next()
  response.cookies.set('vercel', 'fast')
  response.cookies.set({
    name: 'vercel',
    value: 'fast',
    path: '/',
  })
  cookie = response.cookies.get('vercel')
  console.log(cookie) // => { name: 'vercel', value: 'fast', Path: '/' }
  // Die ausgehende Antwort hat einen `Set-Cookie:vercel=fast;path=/`-Header.

  return response
}

Header setzen

Sie können Anfrage- und Antwort-Header mit der NextResponse-API setzen (das Setzen von Anfrage-Headern ist seit Next.js v13.0.0 verfügbar).

import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

export function middleware(request: NextRequest) {
  // Die Anfrage-Header klonen und einen neuen Header `x-hello-from-middleware1` setzen
  const requestHeaders = new Headers(request.headers)
  requestHeaders.set('x-hello-from-middleware1', 'hello')

  // Sie können Anfrage-Header auch in NextResponse.next setzen
  const response = NextResponse.next({
    request: {
      // Neue Anfrage-Header
      headers: requestHeaders,
    },
  })

  // Einen neuen Antwort-Header `x-hello-from-middleware2` setzen
  response.headers.set('x-hello-from-middleware2', 'hello')
  return response
}

Gut zu wissen: Vermeiden Sie das Setzen großer Header, da dies je nach Konfiguration Ihres Backend-Webservers zu einem 431 Request Header Fields Too Large-Fehler führen kann.

CORS

Sie können CORS-Header in der Middleware setzen, um Cross-Origin-Anfragen zu ermöglichen, einschließlich einfacher und preflight-Anfragen.

import { NextRequest, NextResponse } from 'next/server'

const allowedOrigins = ['https://acme.com', 'https://my-app.org']

const corsOptions = {
  'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
  'Access-Control-Allow-Headers': 'Content-Type, Authorization',
}

export function middleware(request: NextRequest) {
  // Die Herkunft aus der Anfrage überprüfen
  const origin = request.headers.get('origin') ?? ''
  const isAllowedOrigin = allowedOrigins.includes(origin)

  // Preflight-Anfragen behandeln
  const isPreflight = request.method === 'OPTIONS'

  if (isPreflight) {
    const preflightHeaders = {
      ...(isAllowedOrigin && { 'Access-Control-Allow-Origin': origin }),
      ...corsOptions,
    }
    return NextResponse.json({}, { headers: preflightHeaders })
  }

  // Einfache Anfragen behandeln
  const response = NextResponse.next()

  if (isAllowedOrigin) {
    response.headers.set('Access-Control-Allow-Origin', origin)
  }

  Object.entries(corsOptions).forEach(([key, value]) => {
    response.headers.set(key, value)
  })

  return response
}

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

Gut zu wissen: Sie können CORS-Header für einzelne Routen in Route Handlers konfigurieren.

Erzeugen einer Antwort

Sie können direkt aus der Middleware heraus antworten, indem Sie eine Response- oder NextResponse-Instanz zurückgeben. (Dies ist seit Next.js v13.1.0 verfügbar)

import type { NextRequest } from 'next/server'
import { isAuthenticated } from '@lib/auth'

// Beschränke die Middleware auf Pfade, die mit `/api/` beginnen
export const config = {
  matcher: '/api/:function*',
}

export function middleware(request: NextRequest) {
  // Rufe unsere Authentifizierungsfunktion auf, um die Anfrage zu prüfen
  if (!isAuthenticated(request)) {
    // Antworte mit JSON, das eine Fehlermeldung anzeigt
    return Response.json(
      { success: false, message: 'authentication failed' },
      { status: 401 }
    )
  }
}

waitUntil und NextFetchEvent

Das NextFetchEvent-Objekt erweitert das native FetchEvent-Objekt und enthält die waitUntil()-Methode.

Die waitUntil()-Methode nimmt ein Promise als Argument und verlängert die Lebensdauer der Middleware, bis das Promise erfüllt ist. Dies ist nützlich für Hintergrundarbeiten.

middleware.ts
import { NextResponse } from 'next/server'
import type { NextFetchEvent, NextRequest } from 'next/server'

export function middleware(req: NextRequest, event: NextFetchEvent) {
  event.waitUntil(
    fetch('https://my-analytics-platform.com', {
      method: 'POST',
      body: JSON.stringify({ pathname: req.nextUrl.pathname }),
    })
  )

  return NextResponse.next()
}

Erweiterte Middleware-Flags

In v13.1 von Next.js wurden zwei zusätzliche Flags für Middleware eingeführt: skipMiddlewareUrlNormalize und skipTrailingSlashRedirect für erweiterte Anwendungsfälle.

skipTrailingSlashRedirect deaktiviert Next.js-Weiterleitungen für das Hinzufügen oder Entfernen von nachgestellten Schrägstrichen. Dies ermöglicht eine benutzerdefinierte Behandlung innerhalb der Middleware, um den nachgestellten Schrägstrich für einige Pfade beizubehalten, aber nicht für andere, was inkrementelle Migrationen erleichtern kann.

next.config.js
module.exports = {
  skipTrailingSlashRedirect: true,
}
middleware.js
const legacyPrefixes = ['/docs', '/blog']

export default async function middleware(req) {
  const { pathname } = req.nextUrl

  if (legacyPrefixes.some((prefix) => pathname.startsWith(prefix))) {
    return NextResponse.next()
  }

  // Behandlung nachgestellter Schrägstriche anwenden
  if (
    !pathname.endsWith('/') &&
    !pathname.match(/((?!\.well-known(?:\/.*)?)(?:[^/]+\/)*[^/]+\.\w+)/)
  ) {
    return NextResponse.redirect(
      new URL(`${req.nextUrl.pathname}/`, req.nextUrl)
    )
  }
}

skipMiddlewareUrlNormalize ermöglicht das Deaktivieren der URL-Normalisierung in Next.js, um direkte Besuche und Client-Übergänge gleich zu behandeln. In einigen erweiterten Fällen bietet diese Option die vollständige Kontrolle durch Verwendung der ursprünglichen URL.

next.config.js
module.exports = {
  skipMiddlewareUrlNormalize: true,
}
middleware.js
export default async function middleware(req) {
  const { pathname } = req.nextUrl

  // GET /_next/data/build-id/hello.json

  console.log(pathname)
  // mit dem Flag ist dies nun /_next/data/build-id/hello.json
  // ohne das Flag würde dies zu /hello normalisiert werden
}

Unit-Tests (experimentell)

Ab Next.js 15.1 enthält das Paket next/experimental/testing/server Hilfsmittel zum Unit-Testen von Middleware-Dateien. Unit-Tests für Middleware können sicherstellen, dass sie nur auf gewünschten Pfaden ausgeführt wird und dass benutzerdefinierte Routing-Logik wie beabsichtigt funktioniert, bevor Code in die Produktion gelangt.

Die Funktion unstable_doesMiddlewareMatch kann verwendet werden, um zu prüfen, ob die Middleware für die bereitgestellte URL, Header und Cookies ausgeführt wird.

import { unstable_doesMiddlewareMatch } from 'next/experimental/testing/server'

expect(
  unstable_doesMiddlewareMatch({
    config,
    nextConfig,
    url: '/test',
  })
).toEqual(false)

Die gesamte Middleware-Funktion kann ebenfalls getestet werden.

import { isRewrite, getRewrittenUrl } from 'next/experimental/testing/server'

const request = new NextRequest('https://nextjs.org/docs')
const response = await middleware(request)
expect(isRewrite(response)).toEqual(true)
expect(getRewrittenUrl(response)).toEqual('https://other-domain.com/docs')
// getRedirectUrl könnte auch verwendet werden, wenn die Antwort eine Weiterleitung wäre

Laufzeitumgebung

Middleware verwendet standardmäßig die Edge-Laufzeitumgebung. Ab v15.2 (canary) gibt es experimentelle Unterstützung für die Node.js-Laufzeitumgebung. Um dies zu aktivieren, fügen Sie das Flag zu Ihrer next.config-Datei hinzu:

import type { NextConfig } from 'next'

const nextConfig: NextConfig = {
  experimental: {
    nodeMiddleware: true,
  },
}

export default nextConfig

Dann setzen Sie in Ihrer Middleware-Datei die Laufzeitumgebung in dem config-Objekt auf nodejs:

export const config = {
  runtime: 'nodejs',
}

Hinweis: Diese Funktion wird für den Produktionseinsatz noch nicht empfohlen. Daher wird Next.js einen Fehler ausgeben, es sei denn, Sie verwenden die next@canary-Version anstelle der stabilen Version.

Plattformunterstützung

BereitstellungsoptionUnterstützt
Node.js-ServerJa
Docker-ContainerJa
Statischer ExportNein
AdapterPlattformspezifisch

Erfahren Sie, wie Sie Middleware konfigurieren, wenn Sie Next.js selbst hosten.

Versionsverlauf

VersionÄnderungen
v15.2.0Middleware kann nun die Node.js-Laufzeitumgebung nutzen (experimentell)
v13.1.0Erweiterte Middleware-Flags hinzugefügt
v13.0.0Middleware kann Anfrage-Header, Antwort-Header modifizieren und Antworten senden
v12.2.0Middleware ist stabil, siehe Upgrade-Guide
v12.0.9Erzwingung absoluter URLs in der Edge-Laufzeitumgebung (PR)
v12.0.0Middleware (Beta) hinzugefügt

On this page