मिडलवेयर
middleware.ts: हर रिक्वेस्ट से पहले config.matcher के साथ रीडायरेक्ट, रीराइट, हेडर और कुकी।
मिडलवेयर रिक्वेस्ट पूरी होने से पहले कोड चलाता है। यह रीडायरेक्ट कर सकता है, री़राइट कर सकता है, हेडर और कुकी सेट कर सकता है या ख़ुद रिस्पॉन्स लौटा सकता है।
कन्वेंशन
प्रोजेक्ट रूट (या src/) में, app/ के बगल में middleware.ts फ़ाइल बनाएं। एक middleware फ़ंक्शन (या डिफ़ॉल्ट एक्सपोर्ट) और एक वैकल्पिक config एक्सपोर्ट करें।
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*"],};text dev, text start और हर सर्वर डिप्लॉय अडैप्टर पर मिडलवेयर रूट हैंडलर, स्टैटिक फ़ाइलों और कंसोल पेजों से पहले चलता है। यह Web Request और Response इस्तेमाल करता है, इसलिए वही फ़ाइल Node, Bun, Vercel Edge और Cloudflare Workers पर चलती है।
पाथ मैच करना
config.matcher के बिना मिडलवेयर हर रिक्वेस्ट के लिए चलता है। मैचर Next.js वाला सिंटैक्स इस्तेमाल करते हैं:
| मैचर | मैच होने वाले पाथ |
|---|---|
/about | /about और /about/ |
/blog/:slug | /blog/hello |
/docs/:path* | /docs, /docs/a/b |
/a/:rest+ | /a/b, /a नहीं |
/user/:id(\\d+) | /user/42, /user/ada नहीं |
/((?!api/).*) | /api/* के अलावा सब कुछ |
has और missing से शर्तें जोड़ें (हेडर, कुकी, क्वेरी या होस्ट):
export const config = { matcher: [{ source: "/beta/:path*", has: [{ type: "cookie", key: "beta", value: "1" }] }],};मैचर basePath के बिना पाथनेम पर लागू होते हैं। text dev में Vite की अपनी मॉड्यूल रिक्वेस्ट (/@vite/*, सोर्स फ़ाइलें) कभी मिडलवेयर नहीं चलातीं।
मिडलवेयर चलने से पहले हर होस्ट एक कैनॉनिकल पाथनेम तय करता है और उसे मैचिंग, request.nextUrl और रूट, हैंडलर व फ़ाइल खोजने के लिए इस्तेमाल करता है। पर्सेंट-एस्केप डिकोड होते हैं और पाथ उसी तरह दोबारा एनकोड होता है जैसे new URL() उसे लिखता है, . और .. सेगमेंट रिज़ॉल्व होते हैं और दोहराए गए व अंत के स्लैश हट जाते हैं। /ad%6din//users/ मिडलवेयर तक /admin/users के रूप में पहुंचता है, जबकि /café का रूप /caf%C3%A9 रहता है। अंत में स्लैश के साथ लिखा मैचर, जैसे /admin/, पाथ /admin से मैच करता है। जिन रिक्वेस्ट के पाथ में एनकोड किया हुआ स्लैश या बैकस्लैश (%2F, %5C), कंट्रोल कैरेक्टर या अमान्य पर्सेंट-एनकोडिंग हो, उन्हें 400 मिलता है। रूट केस-सेंसिटिव हैं: /Admin, पाथ /admin से मैच नहीं करता और स्टैटिक फ़ाइलें सिर्फ़ उनके सटीक नाम पर सर्व होती हैं।
उन URL को मैच करें जिन पर फ़ाइल सर्व होती है, सिर्फ़ उसके फ़ाइल नाम को नहीं। Cloudflare Pages report.html को /report पर भी सर्व करता है, इसलिए /report.html का मैचर /report को सुरक्षित नहीं करता। दोनों को सूची में रखें, matcher: ["/report", "/report.html"], या सुरक्षित फ़ाइलों को एक डायरेक्टरी में रखें और उसे मैच करें, जैसे public/reports/ की फ़ाइलों के लिए /reports/:path*।
NextResponse
| API | असर |
|---|---|
NextResponse.next() | रूट की ओर आगे बढ़ें |
NextResponse.redirect(url, status?) | डिफ़ॉल्ट रूप से 307; url ऐब्सोल्यूट होना चाहिए |
NextResponse.rewrite(url) | दूसरा पाथ सर्व करें; बाहरी ऑरिजिन प्रॉक्सी होते हैं |
NextResponse.json(body, init?) | JSON के साथ रिस्पॉन्स दें |
new Response(...) | किसी भी चीज़ के साथ रिस्पॉन्स दें |
बिना बदलाव के आगे बढ़ने के लिए कुछ न लौटाएं। अंतिम रिस्पॉन्स का स्टेटस बदलने के लिए next() और rewrite(), { status } स्वीकार करते हैं। सिर्फ़ NextResponse.next() / NextResponse.rewrite() से बने रिस्पॉन्स रूटिंग तय करते हैं: कोई भी अन्य Response, जिसमें fetch() से लौटा रिस्पॉन्स भी शामिल है, उसके x-middleware-* हेडर हटाकर क्लाइंट को ज्यों का त्यों भेजा जाता है।
request.nextUrl अपने pathname में basePath को शामिल नहीं करता, जबकि उसके href और toString() इसे शामिल करते हैं। ऐप के अंदर बने रहने के लिए इसे क्लोन करें: 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)); }}हेडर
डाउनस्ट्रीम हैंडलर को क्या मिलता है यह बदलने के लिए request.headers पास करें और रिस्पॉन्स हेडर जोड़ने के लिए headers पास करें:
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;}मिडलवेयर के रिस्पॉन्स हेडर अंतिम रिस्पॉन्स में जुड़ते हैं, जब तक रूट हैंडलर वही हेडर सेट न करे।
कुकी
request.cookies, Cookie हेडर पढ़ता है; response.cookies, Set-Cookie लिखता है।
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() या rewrite() रिस्पॉन्स पर सेट की गई कुकी उसी रिक्वेस्ट में रूट हैंडलर को भी दिखती हैं।
बैकग्राउंड का काम
दूसरे आर्ग्युमेंट में waitUntil() है, जो रिस्पॉन्स भेजने के बाद सर्वरलेस रनटाइम को चालू रखता है:
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 }));}नोट
- क्लाइंट-रेंडर्ड पेज ब्राउज़र में रेंडर होते हैं, इसलिए दूसरे पेज पर री़राइट करने से यह बदलता है कि कौन-सी फ़ाइल सर्व होगी, यह नहीं कि कंसोल ऐप कौन-सा रूट रेंडर करेगा। रूट हैंडलर, स्टैटिक फ़ाइलों और बाहरी ऑरिजिन पर री़राइट उम्मीद के मुताबिक काम करते हैं।
- मिडलवेयर रिक्वेस्ट बॉडी पढ़ सकता है; रूट हैंडलर को फिर भी वह मिलती है। मैचर जिन रिक्वेस्ट को बाहर रखता है, उनकी बॉडी को कभी छुआ नहीं जाता।
request.urlमें हमेशा सर्वर का ऑरिजिन होता है://other.host/xजैसे रिक्वेस्ट टारगेट को शुरुआत में एक ही स्लैश वाले रूप में नॉर्मलाइज़ किया जाता है।- स्टैटिक अडैप्टर मिडलवेयर नहीं चला सकता।