介紹
Next.js 中間件在每個請求之前執行,在邊緣或無伺服器區域運行。專案根目錄下的單一 middleware.ts 檔案會攔截傳入要求,並且可以在請求到達匹配路由之前重定向、重寫、操作標頭或執行驗證檢查。
中間件非常適合在頁面渲染之前進行快速、基於邊緣的決策。預設情況下,它不在靜態資源或 _next/static 上運作。
基本結構
中間件檔案匯出一個接收 NextRequest 並傳回 NextResponse 的函數,以及定義哪些路徑觸發執行的 config 物件。
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";
export function middleware(request: NextRequest) {
console.log(`Request: ${request.nextUrl.pathname}`);
return NextResponse.next();
}
export const config = {
matcher: ["/((?!api|_next/static|_next/image|favicon.ico).*)"],
};
matcher 配置使用帶有負向前瞻的路徑到正規表示式語法來排除靜態檔案。對於特定於部分的中間件,請使用多種模式,例如 ['/dashboard/:path*', '/admin/:path*']。
認證與授權
在中間件中處理身份驗證優於每頁檢查,因為它提供了單一事實來源並消除了頁面轉換時的閃爍。
export function middleware(request: NextRequest) {
const token = request.cookies.get("session")?.value;
const { pathname } = request.nextUrl;
if (!token && pathname.startsWith("/dashboard")) {
return NextResponse.redirect(new URL("/login", request.url));
}
if (token && pathname.startsWith("/login")) {
return NextResponse.redirect(new URL("/dashboard", request.url));
}
return NextResponse.next();
}
對於基於角色的訪問,請在允許訪問管理路由之前解碼 JWT 或會話令牌並檢查使用者的角色。 NextAuth.js、Clerk 和 Auth0 都提供了簡化此過程的中間件助手。
請求重寫和重定向
中間件支援兩種類型的 URL 操作。重寫可在不更改瀏覽器 URL 的情況下提供不同的內容,而重定向則完全更改 URL。
export function middleware(request: NextRequest) {
const { pathname, hostname } = request.nextUrl;
const tenant = hostname.split(".")[0];
if (tenant && tenant !== "www") {
request.nextUrl.pathname = `/${tenant}${pathname}`;
return NextResponse.rewrite(request.nextUrl);
}
}
常見用例包括本地化登陸頁面、功能門控內容以及基於子網域或 cookie 值的多租用戶路由。
地理位置和個性化
邊緣中間件透過 request.geo 提供地理位置數據,包括城市、國家、地區、緯度和經度。 request.ip 屬性給予客戶端 IP 位址。
export function middleware(request: NextRequest) {
const { country } = request.geo;
const { pathname } = request.nextUrl;
if (["DE", "FR", "IT", "ES", "NL"].includes(country) && !pathname.startsWith("/gdpr")) {
return NextResponse.redirect(new URL("/gdpr", request.url));
}
return NextResponse.next();
}
地方定價、內容本地化和 GDPR 同意路由都是基於地理位置的中間件邏輯的實際應用。
邊緣運轉時限制
中間件運行在 Edge Runtime 上,它有重要的限制:
| 限制 | 詳情 |
|---|---|
| Node.js API | 不可用(無檔案系統、加密、路徑) |
| 最大執行 | 30 秒(目標是 1 秒以內) |
| 捆綁尺寸 | 1 MB 限制(程式碼加上依賴項) |
| 資料庫 | 無直接聯繫;使用 API 路由 |
保持中間件邏輯精簡。使用 API 路由或伺服器元件進行繁重的運算、資料庫存取或檔案系統操作。
結論
使用中間件進行快速、基於邊緣的決策,例如身份驗證、重定向和 URL 重寫。保持邏輯簡單,因為它在每個匹配的請求上運行。為了效能,優先使用 matcher 配置而不是函數內部的條件檢查。使用 Playwright 或 Cypress 等工具將中介軟體行為與頁面邏輯分開測試。

