Middleware

Middleware ermöglicht es Ihnen, Code auszuführen, bevor eine Anfrage abgeschlossen wird. Basierend auf der eingehenden Anfrage können Sie die Antwort durch Umschreiben, Weiterleiten, Ändern der Anfrage- oder Antwortheader oder durch direkte Antwort modifizieren.

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

Konvention

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

Beispiel

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

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

// Siehe "Pfadabgleich" unten für weitere Informationen
export const config = {
  matcher: '/about/:path*',
}
import { NextResponse } from 'next/server'

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

// Siehe "Pfadabgleich" unten für weitere Informationen
export const config = {
  matcher: '/about/:path*',
}

Pfadabgleich

Middleware wird für jede Route in Ihrem Projekt aufgerufen. Die folgende Reihenfolge wird eingehalten:

  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 die 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 volle Regex-Unterstützung, sodass Abgleiche wie negative Lookaheads oder Zeichenabgleiche möglich sind. Ein Beispiel für einen negativen Lookahead, um alle Pfade außer bestimmten abzugleichen, sieht folgendermaßen aus:

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

Wichtig: 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.

Wichtig: 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))
  }
}
import { NextResponse } from 'next/server'

export function middleware(request) {
  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 Ihnen:

  • Die eingehende Anfrage auf eine andere URL umzuleiten
  • Die Antwort durch Anzeige einer bestimmten URL umzuschreiben
  • Anfrageheader für API-Routen, getServerSideProps und rewrite-Ziele zu setzen
  • Antwort-Cookies zu setzen
  • Antwortheader zu setzen

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

  1. Auf eine Route (Page oder Edge API Route) 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 über die cookies-Erweiterung von NextRequest und NextResponse zu manipulieren.

  1. Für eingehende Anfragen bietet cookies folgende Methoden: get, getAll, set und delete Cookies. Sie können mit has auf die Existenz eines Cookies prüfen oder mit clear alle Cookies entfernen.
  2. Für ausgehende Antworten bieten 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=/test`-Header.

  return response
}
import { NextResponse } from 'next/server'

export function middleware(request) {
  // 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=/test`-Header.

  return response
}

Header setzen

Sie können Anfrage- und Antwortheader 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 Anfrageheader 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 Anfrageheader auch in NextResponse.rewrite setzen
  const response = NextResponse.next({
    request: {
      // Neue Anfrageheader
      headers: requestHeaders,
    },
  })

  // Einen neuen Antwortheader `x-hello-from-middleware2` setzen
  response.headers.set('x-hello-from-middleware2', 'hello')
  return response
}
import { NextResponse } from 'next/server'

export function middleware(request) {
  // Die Anfrageheader 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 Anfrageheader auch in NextResponse.rewrite setzen
  const response = NextResponse.next({
    request: {
      // Neue Anfrageheader
      headers: requestHeaders,
    },
  })

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

Wichtig: 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.

Antwort erzeugen

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

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

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

export function middleware(request: NextRequest) {
  // Unsere Authentifizierungsfunktion aufrufen, um die Anfrage zu prüfen
  if (!isAuthenticated(request)) {
    // Mit JSON antworten, das eine Fehlermeldung anzeigt
    return Response.json(
      { success: false, message: 'Authentifizierung fehlgeschlagen' },
      { status: 401 }
    )
  }
}
import { isAuthenticated } from '@lib/auth'

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

export function middleware(request) {
  // Unsere Authentifizierungsfunktion aufrufen, um die Anfrage zu prüfen
  if (!isAuthenticated(request)) {
    // Mit JSON antworten, das eine Fehlermeldung anzeigt
    return Response.json(
      { success: false, message: 'Authentifizierung fehlgeschlagen' },
      { status: 401 }
    )
  }
}

Erweiterte Middleware-Flags

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

skipTrailingSlashRedirect ermöglicht das Deaktivieren der standardmäßigen Next.js-Weiterleitungen für das Hinzufügen oder Entfernen von nachgestellten Schrägstrichen, wodurch eine benutzerdefinierte Behandlung innerhalb der Middleware ermöglicht wird. Dies kann das Beibehalten des nachgestellten Schrägstrichs für einige Pfade, aber nicht für andere erleichtern, was schrittweise Migrationen vereinfacht.

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+)/)
  ) {
    req.nextUrl.pathname += '/'
    return NextResponse.redirect(req.nextUrl)
  }
}

skipMiddlewareUrlNormalize ermöglicht das Deaktivieren der URL-Normalisierung, die Next.js durchführt, um den Umgang mit direkten Besuchen und Client-Übergängen gleich zu machen. Es gibt einige erweiterte Fälle, in denen Sie die volle Kontrolle über die ursprüngliche URL benötigen, was dieses Flag ermöglicht.

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 jetzt /_next/data/build-id/hello.json
  // Ohne das Flag würde dies zu /hello normalisiert werden
}

Versionsverlauf

VersionÄnderungen
v13.1.0Erweiterte Middleware-Flags hinzugefügt
v13.0.0Middleware kann Anfrageheader, Antwortheader ändern und Antworten senden
v12.2.0Middleware ist stabil, bitte siehe Upgrade-Leitfaden
v12.0.9Absolute URLs in Edge Runtime erzwingen (PR)
v12.0.0Middleware (Beta) hinzugefügt