Middleware

middleware.ts: Weiterleitungen, Rewrites, Header und Cookies vor jeder Anfrage, mit config.matcher.

Middleware führt Code aus, bevor eine Anfrage abgeschlossen ist. Sie kann weiterleiten, umschreiben, Header und Cookies setzen oder selbst eine Antwort zurückgeben.

Konvention

Erstelle middleware.ts im Projektstammverzeichnis (oder in src/), neben app/. Exportiere eine middleware-Funktion (oder einen Standardexport) und optional eine config.

middleware.tsts
import { NextResponse, type NextRequest } from "@textjs/app/server";export function middleware(request: NextRequest) {  if (!request.cookies.has("session")) {    return NextResponse.redirect(new URL("/login", request.url));  }  return NextResponse.next();}export const config = {  matcher: ["/dashboard/:path*", "/api/:path*"],};

Middleware läuft vor Route-Handlern, statischen Dateien und Konsolenseiten, unter text dev, text start und jedem serverseitigen Deploy-Adapter. Sie verwendet die Web-APIs Request und Response, sodass dieselbe Datei auf Node, Bun, Vercel Edge und Cloudflare Workers läuft.

Pfade abgleichen

Ohne config.matcher läuft Middleware bei jeder Anfrage. Matcher verwenden dieselbe Syntax wie Next.js:

MatcherTreffer
/about/about und /about/
/blog/:slug/blog/hello
/docs/:path*/docs, /docs/a/b
/a/:rest+/a/b, nicht /a
/user/:id(\\d+)/user/42, nicht /user/ada
/((?!api/).*)Alles außer /api/*

Füge mit has und missing Bedingungen hinzu (Header, Cookie, Abfrage oder Host):

middleware.tsts
export const config = {  matcher: [{ source: "/beta/:path*", has: [{ type: "cookie", key: "beta", value: "1" }] }],};

Matcher gelten für den Pfadnamen ohne basePath. Unter text dev lösen Vites eigene Modulanfragen (/@vite/*, Quelldateien) niemals Middleware aus.

Jeder Host ermittelt vor der Ausführung der Middleware einen kanonischen Pfadnamen und verwendet ihn für den Abgleich, request.nextUrl und die Suche nach Routen, Handlern und Dateien. Prozentkodierungen werden dekodiert und der Pfad so neu kodiert, wie new URL() ihn schreibt, die Segmente . und .. werden aufgelöst und wiederholte sowie abschließende Schrägstriche entfernt. /ad%6din//users/ erreicht die Middleware als /admin/users, während /café als /caf%C3%A9 erhalten bleibt. Ein Matcher mit abschließendem Schrägstrich, etwa /admin/, trifft auf /admin zu. Anfragen, deren Pfad einen kodierten Schrägstrich oder Rückstrich (%2F, %5C), ein Steuerzeichen oder eine ungültige Prozentkodierung enthält, erhalten 400. Routen unterscheiden Groß- und Kleinschreibung: /Admin passt nicht zu /admin, und statische Dateien werden nur unter ihrem exakten Namen ausgeliefert.

Gleiche die URLs ab, unter denen eine Datei ausgeliefert wird, nicht nur ihren Dateinamen. Cloudflare Pages liefert report.html auch unter /report aus, daher schützt ein Matcher für /report.html nicht /report. Führe beide auf, matcher: ["/report", "/report.html"], oder lege geschützte Dateien in einem Verzeichnis ab und gleiche dieses ab, etwa mit /reports/:path* für Dateien in public/reports/.

NextResponse

APIWirkung
NextResponse.next()Mit der Route fortfahren
NextResponse.redirect(url, status?)Standardmäßig 307; url muss absolut sein
NextResponse.rewrite(url)Einen anderen Pfad ausliefern; externe Ursprünge werden über einen Proxy eingebunden
NextResponse.json(body, init?)Mit JSON antworten
new Response(...)Mit beliebigem Inhalt antworten

Gib nichts zurück, um unverändert fortzufahren. next() und rewrite() akzeptieren { status }, um den Status der endgültigen Antwort zu ändern. Nur Antworten, die mit NextResponse.next() / NextResponse.rewrite() erstellt wurden, steuern das Routing: Jede andere Response, einschließlich einer von fetch() zurückgegebenen, wird unverändert an den Client gesendet, wobei ihre x-middleware-*-Header entfernt werden.

request.nextUrl schließt basePath aus pathname aus, während href und toString() es enthalten. Um innerhalb der App zu bleiben, klone es: const url = request.nextUrl.clone(); url.pathname = "/login"; return NextResponse.redirect(url);.

middleware.tsts
export function middleware(request: NextRequest) {  if (request.nextUrl.pathname === "/status") {    return NextResponse.rewrite(new URL("/api/health", request.url));  }}

Header

Übergib request.headers, um zu ändern, was nachgelagerte Handler empfangen, und headers, um Antwort-Header hinzuzufügen:

middleware.tsts
export function middleware(request: NextRequest) {  const headers = new Headers(request.headers);  headers.set("x-user", "ada");  const response = NextResponse.next({ request: { headers } });  response.headers.set("x-frame", "▼");  return response;}

Antwort-Header aus der Middleware werden der endgültigen Antwort hinzugefügt, sofern der Route-Handler nicht denselben Header setzt.

Cookies

request.cookies liest den Cookie-Header; response.cookies schreibt Set-Cookie.

middleware.tsts
export function middleware(request: NextRequest) {  const theme = request.cookies.get("theme")?.value ?? "geistDark";  const response = NextResponse.next();  response.cookies.set("theme", theme, { httpOnly: true, sameSite: "lax", maxAge: 60 * 60 * 24 });  return response;}

Cookies, die in einer next()- oder rewrite()-Antwort gesetzt werden, sind auch für den Route-Handler innerhalb derselben Anfrage sichtbar.

Hintergrundaufgaben

Das zweite Argument bietet waitUntil(), das serverlose Laufzeitumgebungen nach dem Senden der Antwort aktiv hält:

middleware.tsts
import type { NextFetchEvent, NextRequest } from "@textjs/app/server";export function middleware(request: NextRequest, event: NextFetchEvent) {  event.waitUntil(fetch("https://analytics.example.com", { method: "POST", body: request.url }));}

Hinweise

  • Clientseitig gerenderte Seiten rendern im Browser, daher ändert eine Umschreibung auf eine andere Seite, welche Datei ausgeliefert wird, nicht welche Route die Konsolen-App rendert. Umschreibungen auf Route-Handler, statische Dateien und externe Ursprünge verhalten sich wie erwartet.
  • Middleware kann den Anfrage-Body lesen; Route-Handler erhalten ihn weiterhin. Der Body von Anfragen, die ein Matcher ausschließt, bleibt unangetastet.
  • request.url hat immer den Ursprung des Servers: Anfrageziele wie //other.host/x werden auf einen einzelnen führenden Schrägstrich normalisiert.
  • Der statische Adapter kann keine Middleware ausführen.
Diese Seite auf GitHub bearbeiten