Middleware

middleware.ts: przekierowania, przepisywanie adresów, nagłówki i ciasteczka przed każdym żądaniem, z config.matcher.

Middleware uruchamia kod przed zakończeniem żądania. Może przekierowywać, przepisywać adresy, ustawiać nagłówki i pliki cookie lub samodzielnie zwracać odpowiedź.

Konwencja

Utwórz middleware.ts w katalogu głównym projektu (lub w src/), obok app/. Wyeksportuj funkcję middleware (lub eksport domyślny) oraz opcjonalny 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 uruchamia się przed handlerami tras, plikami statycznymi i stronami konsoli, w text dev, text start i każdym serwerowym adapterze wdrożeniowym. Korzysta z interfejsów Web Request i Response, więc ten sam plik działa w środowiskach Node, Bun, Vercel Edge i Cloudflare Workers.

Dopasowywanie ścieżek

Bez config.matcher middleware uruchamia się dla każdego żądania. Wzorce dopasowania używają tej samej składni co Next.js:

WzorzecDopasowania
/about/about i /about/
/blog/:slug/blog/hello
/docs/:path*/docs, /docs/a/b
/a/:rest+/a/b, ale nie /a
/user/:id(\\d+)/user/42, ale nie /user/ada
/((?!api/).*)Wszystko oprócz /api/*

Dodaj warunki za pomocą has i missing (nagłówek, plik cookie, zapytanie lub host):

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

Wzorce dopasowania dotyczą ścieżki bez basePath. W text dev żądania własnych modułów Vite (/@vite/*, pliki źródłowe) nigdy nie uruchamiają middleware.

Każdy host ustala jedną kanoniczną ścieżkę przed uruchomieniem middleware i używa jej do dopasowywania, w request.nextUrl oraz do wyszukiwania trasy, handlera i pliku. Sekwencje procentowe są dekodowane, a ścieżka jest ponownie kodowana tak, jak zapisuje ją new URL(); segmenty . i .. są rozwiązywane, a powtórzone i końcowe ukośniki usuwane. /ad%6din//users/ dociera do middleware jako /admin/users, natomiast /café pozostaje /caf%C3%A9. Wzorzec z końcowym ukośnikiem, taki jak /admin/, dopasowuje /admin. Żądania, których ścieżka zawiera zakodowany ukośnik lub ukośnik odwrotny (%2F, %5C), znak sterujący lub nieprawidłowe kodowanie procentowe, otrzymują 400. Trasy rozróżniają wielkość liter: /Admin nie pasuje do /admin, a pliki statyczne są udostępniane wyłącznie pod swoją dokładną nazwą.

Dopasuj adresy URL, pod którymi plik jest udostępniany, nie tylko jego nazwę. Cloudflare Pages udostępnia report.html także pod /report, więc wzorzec dla /report.html nie chroni /report. Wymień oba adresy, matcher: ["/report", "/report.html"], lub przechowuj chronione pliki w katalogu i dopasuj go, na przykład za pomocą /reports/:path* dla plików w public/reports/.

NextResponse

APIEfekt
NextResponse.next()Przejście do trasy
NextResponse.redirect(url, status?)Domyślnie 307; url musi być bezwzględny
NextResponse.rewrite(url)Udostępnienie innej ścieżki; zewnętrzne źródła są obsługiwane przez proxy
NextResponse.json(body, init?)Odpowiedź w formacie JSON
new Response(...)Odpowiedź z dowolną zawartością

Nie zwracaj niczego, aby kontynuować bez zmian. next() i rewrite() przyjmują { status }, aby zmienić status końcowej odpowiedzi. Tylko odpowiedzi utworzone przez NextResponse.next() / NextResponse.rewrite() sterują routingiem: każda inna Response, także zwrócona przez fetch(), trafia do klienta bez zmian po usunięciu nagłówków x-middleware-*.

request.nextUrl pomija basePath w pathname, natomiast jego href i toString() go uwzględniają. Aby pozostać w obrębie aplikacji, sklonuj go: 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));  }}

Nagłówki

Przekaż request.headers, aby zmienić to, co otrzymują kolejne handlery, oraz headers, aby dodać nagłówki odpowiedzi:

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;}

Nagłówki odpowiedzi z middleware są dodawane do końcowej odpowiedzi, chyba że handler trasy ustawi ten sam nagłówek.

Pliki cookie

request.cookies odczytuje nagłówek Cookie; response.cookies zapisuje 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;}

Pliki cookie ustawione w odpowiedzi next() lub rewrite() są też widoczne dla handlera trasy w tym samym żądaniu.

Praca w tle

Drugi argument udostępnia waitUntil(), które podtrzymuje działanie środowisk serverless po wysłaniu odpowiedzi:

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 }));}

Uwagi

  • Strony renderowane po stronie klienta renderują się w przeglądarce, więc przepisanie adresu na inną stronę zmienia udostępniany plik, a nie trasę renderowaną przez aplikację konsolową. Przepisania do handlerów tras, plików statycznych i zewnętrznych źródeł działają zgodnie z oczekiwaniami.
  • Middleware może odczytać treść żądania; handlery tras nadal ją otrzymują. Treść żądań wykluczonych przez wzorzec dopasowania nigdy nie jest odczytywana ani zmieniana.
  • request.url zawsze ma źródło serwera: cele żądań takie jak //other.host/x są normalizowane do pojedynczego początkowego ukośnika.
  • Adapter statyczny nie może uruchamiać middleware.
Edytuj tę stronę w serwisie GitHub