Ara katman
middleware.ts: config.matcher ile her istek öncesinde yönlendirmeler, yeniden yazmalar, üstbilgiler ve çerezler.
Middleware, bir istek tamamlanmadan önce kod çalıştırır. Yönlendirme yapabilir, yolu yeniden yazabilir, başlıkları ve çerezleri ayarlayabilir veya kendisi bir yanıt döndürebilir.
Dosya düzeni
Proje kökünde (veya src/ içinde), app/ dizininin yanında middleware.ts oluşturun. Bir middleware fonksiyonunu (veya varsayılan bir dışa aktarımı) ve isteğe bağlı bir config dışa aktarın.
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, text dev, text start ve her sunucu dağıtım adaptöründe rota işleyicilerinden, statik dosyalardan ve konsol sayfalarından önce çalışır. Web Request ve Response API’lerini kullanır; böylece aynı dosya Node, Bun, Vercel Edge ve Cloudflare Workers üzerinde çalışır.
Yolları eşleştirme
config.matcher olmadığında middleware her istek için çalışır. Eşleştiriciler Next.js ile aynı sözdizimini kullanır:
| Eşleştirici | Eşleşen yollar |
|---|---|
/about | /about ve /about/ |
/blog/:slug | /blog/hello |
/docs/:path* | /docs, /docs/a/b |
/a/:rest+ | /a/b, ancak /a eşleşmez |
/user/:id(\\d+) | /user/42, ancak /user/ada eşleşmez |
/((?!api/).*) | /api/* dışındaki her şey |
has ve missing ile koşullar ekleyin (başlık, çerez, sorgu veya ana makine):
export const config = { matcher: [{ source: "/beta/:path*", has: [{ type: "cookie", key: "beta", value: "1" }] }],};Eşleştiriciler, basePath olmadan yol adına uygulanır. text dev çalışırken Vite’ın kendi modül istekleri (/@vite/*, kaynak dosyalar) hiçbir zaman middleware çalıştırmaz.
Her barındırma ortamı, middleware çalışmadan önce tek bir standart yol adı belirler ve bunu eşleştirme, request.nextUrl ve rota, işleyici ve dosya araması için kullanır. Yüzde kodlamaları çözülür ve yol, new URL() nasıl yazıyorsa o şekilde yeniden kodlanır; . ve .. bölümleri çözümlenir, yinelenen ve sondaki eğik çizgiler kaldırılır. /ad%6din//users/, middleware’e /admin/users olarak ulaşırken /café, /caf%C3%A9 olarak kalır. /admin/ gibi sonunda eğik çizgi olan bir eşleştirici, /admin ile eşleşir. Yolunda kodlanmış eğik çizgi veya ters eğik çizgi (%2F, %5C), kontrol karakteri veya geçersiz yüzde kodlaması bulunan istekler 400 alır. Rotalar büyük/küçük harfe duyarlıdır: /Admin, /admin ile eşleşmez ve statik dosyalar yalnızca tam adlarıyla sunulur.
Dosyanın adının yanı sıra sunulduğu URL’leri de eşleştirin. Cloudflare Pages, report.html dosyasını /report adresinde de sunar; bu nedenle /report.html için bir eşleştirici /report adresini korumaz. İkisini de matcher: ["/report", "/report.html"] şeklinde listeleyin veya korunan dosyaları bir dizinde tutup bu dizini eşleştirin; örneğin public/reports/ içindeki dosyalar için /reports/:path* kullanın.
NextResponse
| API | Etki |
|---|---|
NextResponse.next() | Rotaya devam etme |
NextResponse.redirect(url, status?) | Varsayılan olarak 307; url mutlak olmalıdır |
NextResponse.rewrite(url) | Başka bir yolu sunma; harici kaynaklara proxy üzerinden erişilir |
NextResponse.json(body, init?) | JSON ile yanıt verme |
new Response(...) | Herhangi bir içerikle yanıt verme |
Değişiklik yapmadan devam etmek için hiçbir şey döndürmeyin. next() ve rewrite(), nihai yanıtın durumunu değiştirmek için { status } kabul eder. Yalnızca NextResponse.next() / NextResponse.rewrite() ile oluşturulan yanıtlar rota seçimini yönlendirir: fetch() çağrısından dönenler dahil diğer tüm Response nesneleri, x-middleware-* başlıkları kaldırılarak istemciye olduğu gibi gönderilir.
request.nextUrl, pathname içinden basePath değerini çıkarır; ancak href ve toString() bu değeri içerir. Uygulama içinde kalmak için bunu klonlayın: const url = request.nextUrl.clone(); url.pathname = "/login"; return NextResponse.redirect(url);.
export function middleware(request: NextRequest) { if (request.nextUrl.pathname === "/status") { return NextResponse.rewrite(new URL("/api/health", request.url)); }}Başlıklar
Sonraki işleyicilerin aldıklarını değiştirmek için request.headers, yanıt başlıkları eklemek için headers geçirin:
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;}Rota işleyicisi aynı başlığı ayarlamadığı sürece middleware’den gelen yanıt başlıkları nihai yanıta eklenir.
Çerezler
request.cookies, Cookie başlığını okur; response.cookies, Set-Cookie başlığını yazar.
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;}next() veya rewrite() yanıtında ayarlanan çerezler, aynı istekte rota işleyicisi tarafından da görülebilir.
Arka plan işlemleri
İkinci argüman, yanıt gönderildikten sonra sunucusuz çalışma ortamlarını açık tutan waitUntil() metodunu içerir:
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 }));}Notlar
- İstemcide render edilen sayfalar tarayıcıda render edilir; bu nedenle başka bir sayfaya yeniden yazma, konsol uygulamasının render ettiği rotayı değil, sunulan dosyayı değiştirir. Rota işleyicilerine, statik dosyalara ve harici kaynaklara yeniden yazmalar beklendiği gibi davranır.
- Middleware istek gövdesini okuyabilir; rota işleyicileri gövdeyi almaya devam eder. Bir eşleştiricinin hariç tuttuğu isteklerin gövdesine hiçbir zaman dokunulmaz.
request.urlher zaman sunucunun kaynağını içerir://other.host/xgibi istek hedefleri, başında tek bir eğik çizgi olacak şekilde normalleştirilir.- Statik adaptör middleware çalıştıramaz.