Next 中的 Middleware 是什麼?
Middleware(中介軟體)是一種在請求 (Request) 到達特定路由或 API 之前執行的函式。在 Next.js 中,Middleware 可用於攔截並修改請求,使開發者能夠靈活地進行身份驗證、請求重寫、日誌記錄等。
與傳統 Express.js 或 Koa.js 的 Middleware 不同,Next.js 的 Middleware 是 Edge Function,運行在 Edge Network(邊緣網絡),因此具有極快的響應速度。
此外,Express.js 的 Middleware 通常運行於伺服器(Server)內部,支援 req.body 解析、動態 API 處理,而 Next.js Middleware 則更偏向於請求前的攔截與修改,適合應用於身份驗證、A/B 測試及 SEO 優化等場景。
所以在 Next.js 中,Middleware 可用於攔截並修改請求,使開發者能夠靈活地進行身份驗證、請求重寫、日誌記錄等。
Middleware 的運行時機
Middleware 在請求剛進入 Next.js 應用之前執行,它通常在 瀏覽器發送請求後、Next.js 處理路由與頁面渲染前 運行,如:
- 用戶從瀏覽器地址列輸入網址並按 Enter
- 點擊網頁上的連結以導向其他頁面
- 透過 JavaScript 發送 AJAX/FETCH 請求
- 表單提交後觸發的請求 (form submit)
Middleware 的基本使用
1. 建立 middleware.js
在 Next.js 應用的 src 或 root 目錄下建立 middleware.js,並貼上以下 code :
import { NextResponse } from 'next/server';
export function middleware(req) {
// 開始你要做的事情
return NextResponse.next();
}
2. 設定 Middleware 作用範圍
如果 Middleware 只需要作用於特定路徑,可在 middleware.js 中加上 config 來設定匹配的路由。
Next.js 提供 matcher 屬性來定義 Middleware 的作用範圍,支援類似路由的模式匹配。例如:
export const config = {
matcher: [
'/dashboard/:path*',
'/admin/:path*'
]
};
這代表 Middleware 只會作用於 /dashboard/
和 /admin/
相關頁面,而不影響其他請求。
Middleware 與 API Routes 的差異
要使用 middleware 前,也先了解一下它與 API Router 的差異在哪,我們可以透過簡單的比較表來看:
比較項目 | Middleware | API Routes |
---|---|---|
運行位置 | 邊緣 (Edge Network) | 應用內 (Server) |
適用場景 | 攔截請求、重寫 URL、身份驗證 | 處理 API 請求、資料庫查詢 |
延遲時間 | 極低(因為運行在 Edge) | 視 Server 性能而定 |
影響範圍 | 整個應用的請求 | 只有 /api/ 路徑 |
Middleware 是在請求 進入應用前 就攔截處理,而 API Routes 則是在應用內部處理特定 API 請求。
舉例來說,假設我們有一個用於管理後台的 /admin 路由:
- Middleware 處理身份驗證:攔截請求並檢查使用者是否具有管理員權限,若無則重定向至 /login。
- API Routes 處理數據請求:在 /api/admin/users 內部執行資料庫查詢並返回 JSON 結果。
這樣的組合能確保應用層級的安全性,同時保持數據存取的靈活性。
Middleware 的限制與注意事項
雖然 middleware 可以攔截請求,但也並非所有資料都可以取得,所以在使用上,需要注意一下相關限制:
1. 不支援 .json() 回應
這是因為 Middleware 運行於 Edge Function,主要設計用於攔截請求與修改 headers 或重定向,並不具備完整的 Response Body 處理能力。
所以 middleware 只能透過 NextResponse 修改/回傳請求,直接回傳 JSON 會出錯。若需要返回 JSON,建議在 API Route (/api/...
) 內部處理。
/*** Wrong example ***/
export function middleware(req) {
return req.json();
}
2. 不支援 fetch()
如果你希望在 middleware 中打 API,那你要失望了,middleware 並不支援 fetch(),原因如下 :
- Middleware 運行在 Edge Functions 環境,而 Edge Functions 並不是完整的 Node.js 環境
- fatch 需要完整的網路 API 支援,受限於 Edge Functions 環境,使用 fatch 可能導致 timeout or 請求失敗
如果你設想中希望在 middleware 階段打 API,你需要這樣:
(1). 先建立 API Router
在 /pages/api/ 底下建立你要的 API,例如 /pages/api/test.js:
export default async function handler(req, res) {
try {
// 執行你預計要打的 API
const response = await fetch("https://api.example.com/test");
const data = await response.json();
res.status(200).json(data);
} catch (error) {
res.status(500).json({ error: "API 請求失敗" });
}
}
(2). Middleware 內部轉發請求至 API Route
import { NextResponse } from "next/server";
export function middleware(req) {
const apiUrl = new URL("/api/test", req.url);
return NextResponse.rewrite(apiUrl);
}
3. 無法存取 body
middleware 中,是無法取得 body的,以下整理一張表格,方便大家快速查看那些可以存取:
// middleware example: req
export function middleware(req) {
return NextResponse.next()
}
屬性 | 可存取 | 可修改 | 說明 |
---|---|---|---|
req.url | ✅ | ❌ | 用於獲取請求的完整 URL |
req.nextUrl | ✅ | ❌ | Next.js 解析過的 URL,適用於 Rewrite/Redirect |
req.method | ✅ | ❌ | 獲取請求方法,如 GET 、POST |
req.headers | ✅ | ❌ | 可讀取請求標頭,如 Authorization 、User-Agent |
req.cookies | ✅ | ❌ | 可讀取與設置 Cookie,如 req.cookies.get('token') |
req.ip | ✅ | ❌ | 取得用戶的 IP 地址 |
req.body | ✅ | ❌ | Middleware 無法讀取 body ,需透過 API Routes 處理 |
4. 運行速度快,但有資料處理大小限制
Middleware 適用 Edge Functions,雖然速度快,但無法與傳統後端 API 相同,不能拿來處理大型數據。
如果你有大量資料處理需求,請避免在此處處理,以免產生中斷等非預期狀況。
結論
Middleware 在 Next.js 中提供了請求攔截功能,同時可以與 Edge Functions 配合使用,在使用上只要了解相關限制,就可以將部分請求處理邏輯前移到邊緣網絡執行,減少伺服器負載,提升應用效能,極大提升應用的性能與安全性。
發表迴響