什么是中間件?
在 Next.js 中,中間件(Middleware)是一種用于處理每個傳入請求的功能。它允許你在請求到達頁面之前對其進行修改或響應。
通過中間件,你可以實現諸如日志記錄
、身份驗證
、重定向
、CORS配置
、壓縮
等任務。中間件是構建高效和安全的 web
應用的重要組成部分。
應用場景
身份驗證
你可以在中間件中檢查用戶的身份驗證狀態,比如從cookie或頭部信息中讀取JWT令牌,并根據驗證結果決定是否允許訪問特定頁面或API端點。如果驗證失敗,可以返回401未授權狀態碼或者重定向到登錄頁面。
示例代碼:
// middleware.js
import { NextResponse } from 'next/server';export function middleware(request) {const token = request.cookies.get('authToken')?.value;if (!token) {// 如果沒有令牌,則重定向到登錄頁面return NextResponse.redirect(new URL('/login', request.url));}// 繼續處理鏈return NextResponse.next();
}
日志記錄
中間件非常適合用來記錄所有進入應用程序的請求。這可以幫助監控流量模式、診斷問題以及了解用戶行為。
示例代碼:
// middleware.js
import { NextResponse } from 'next/server';export function middleware(request) {console.log(`Request to ${request.url} at ${new Date().toISOString()}`);// 繼續處理鏈return NextResponse.next();
}
請求/響應轉換
可以在請求到達最終目的地之前對請求數據進行預處理,也可以在發送給客戶端之前修改響應內容。例如,格式化數據、添加額外的HTTP頭、壓縮響應體等。
示例代碼:
// middleware.js
import { NextResponse } from 'next/server';export async function middleware(request) {// 修改請求體(假設是JSON格式)let modifiedBody = await request.json();modifiedBody.message = "Modified message";// 創建新的請求實例const newReq = new Request(request, {body: JSON.stringify(modifiedBody),});// 獲取響應并修改它const response = await fetch(request.nextUrl.pathname, {method: request.method,headers: request.headers,body: newReq.body,});const resClone = await response.clone();const data = await resClone.json();data.newField = "This is a new field"; // 添加新字段// 返回修改后的響應return new Response(JSON.stringify(data), {status: response.status,headers: response.headers,});
}
重定向
基于某些條件(如URL路徑、查詢參數、用戶代理等),你可以使用中間件來執行重定向操作,將用戶引導至不同的頁面。
示例代碼:
// middleware.js
import { NextResponse } from 'next/server';export function middleware(request) {// 如果訪問的是舊路徑,則重定向到新路徑if (request.nextUrl.pathname.startsWith('/login')) {return NextResponse.redirect(new URL('/dashboard', request.url));}// 繼續處理鏈return NextResponse.next();
}
CORS(跨源資源共享)
設置適當的CORS頭以允許或限制來自其他域的請求,這對于擁有多個子域名或需要與第三方服務交互的應用非常重要。
示例代碼:
// middleware.js
import { NextResponse } from 'next/server';export function middleware(request) {const response = NextResponse.next();// 設置CORS頭response.headers.set('Access-Control-Allow-Origin', '*');response.headers.set('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');response.headers.set('Access-Control-Allow-Headers', 'Content-Type, Authorization');return response;
}
限流
防止濫用API接口,可以通過中間件實現速率限制,限制同一IP地址在一定時間內的請求次數。
示例代碼:
// middleware.js
import { NextResponse } from 'next/server';
import rateLimit from 'express-rate-limit'; // 需要安裝依賴const limiter = rateLimit({windowMs: 1 * 60 * 1000, // 1分鐘max: 100, // 每分鐘最多100次請求
});export function middleware(request) {return new Promise((resolve, reject) => {limiter(request, {}, (err) => {if (err) {return reject(new NextResponse('Too many requests', { status: 429 }));}resolve(NextResponse.next());});});
}
國際化路由
根據用戶的語言偏好或地理位置自動調整網站的語言版本。
示例代碼:
// middleware.js
import { NextResponse } from 'next/server';export function middleware(request) {const locale = request.cookies.get('NEXT_LOCALE')?.value || 'en';// 如果不是根路徑并且沒有包含語言前綴,則添加語言前綴if (!request.nextUrl.pathname.startsWith(`/${locale}`)) {const url = new URL(request.url);url.pathname = `/${locale}${url.pathname}`;return NextResponse.redirect(url);}// 繼續處理鏈return NextResponse.next();
}
靜態文件服務
盡管Next.js已經提供了基本的靜態文件服務功能,但你可以用中間件來增強這一功能,比如為特定類型的文件提供自定義處理邏輯。
示例代碼:
// middleware.js
import { NextResponse } from 'next/server';
import fs from 'fs/promises';export async function middleware(request) {const path = request.nextUrl.pathname;if (path.startsWith('/static-files/')) {try {const filePath = `./public${path}`;const file = await fs.readFile(filePath);return new Response(file, {headers: { 'Content-Type': 'application/octet-stream' },});} catch (error) {return NextResponse.next();}}// 繼續處理鏈return NextResponse.next();
}
config 配置對象
matcher
matcher
是一個非常強大的配置項,它允許你指定中間件應該應用于哪些路徑。你可以通過正則表達式或通配符模式來匹配URL路徑。
通配符
:可以使用*
來表示任意字符序列。正則表達式
:支持完整的正則表達式語法,但需要使用反斜杠進行轉義。
export const config = {matcher: ['/about', '/dashboard/:path*', '/users/:uid'],
};
unstable_ignorePaths
這個配置項可以讓中間件忽略某些路徑,即不對其應用中間件邏輯。這對于排除不需要處理的資源或者避免循環重定向等問題非常有用。
export const config = {unstable_ignorePaths: ['/api/*', '/static/*'],
};
這里,所有以 /api
/開頭和靜態資源路徑都將被忽略,不會受到中間件的影響。
maxDuration
maxDuration
定義了中間件函數的最大執行時間(以秒為單位)。如果中間件執行時間超過了這個值,Next.js將會拋出錯誤。這有助于防止長時間運行的任務阻塞請求處理。
export const config = {maxDuration: 5, // 中間件最大執行時間為5秒
};
regions
regions
配置項指定了中間件應該部署到的地理區域。這對于希望減少延遲、提高性能的應用來說非常重要,因為它可以讓中間件盡可能靠近用戶部署。
export const config = {regions: ['us-east-1', 'eu-west-1'], // 在美國東部和歐洲西部部署
};
下面是一個結合了多個config配置項的例子:
// middleware.js
import { NextResponse } from 'next/server';export function middleware(request) {// 中間件邏輯...return NextResponse.next();
}export const config = {matcher: ['/about', '/dashboard/:path*', '/users/:uid'],unstable_ignorePaths: ['/api/*', '/static/*'],maxDuration: 10,regions: ['us-east-1', 'eu-west-1'],
};
總結
總之,Next.js中間件不僅僅是一個簡單的請求處理器,它更像是一個構建模塊,允許開發者以一種非侵入式的方式對HTTP請求進行預處理和后處理。這不僅簡化了代碼邏輯,提高了代碼的可維護性,而且還有助于創建更加快速、安全和用戶友好的Web體驗。無論你是剛開始接觸Next.js的新手,還是已經熟悉框架的老手,掌握中間件的使用都將為你的項目帶來顯著的價值。
Github
:next-admin
線上預覽地址
:Next Admin