前端框架

-

什麼是 Middleware?Next.js 實戰 Middleware 教學

this.web

你有沒有想過,為什麼有時候我們打開一些國外網站能自動顯示中文版網頁?而不是英文?

背後靠的其實是一個分流機制:Middleware

如果你不清楚他是什麼、怎麼運作,今天這篇文章 5 分鐘帶你搞懂!

什麼是 Middleware?

想像一下,你要去一間餐廳吃飯(=使用者要進入你的網站頁面)。

在你進門之前,門口有一位店員(=Middleware)。

這位店員會先幫你做一些檢查或處理,比如:

  • 看你有沒有訂位(=檢查是否登入)。
  • 如果沒訂位,請你先去旁邊排隊(=redirect 到 login 頁)。
  • 如果你是 VIP,就幫你帶去包廂(=rewrite 到特別的頁面)。
  • 如果你拿著外送袋,他直接把餐點交給你,不用再進去(=直接回應)。

Middleware 就是這個「門口守門員」。它的工作就是在「使用者真的進到網站(餐廳)」之前,先決定要怎麼處理這個請求。

工作好幾年,覺得自己成長不大嗎?

我正在舉辦前端 SR 體驗課,希望用 2.5 小時,幫助你釐清未來職涯方向,並打造接下來 12 個月的技術成長攻略。

如果你希望在接下來一年:

  1. 有計劃地變強,停止自我懷疑
  2. 把學到的技術變成履歷亮點
  3. 成為團隊中前 10% 的工程師

點我免費報名體驗課(有限制名額,趕快報名哦!)

image

什麼時候會觸發 Middleware?

只要有人「要進你網站的路由」,Middleware 就會先跑一次。具體流程會像這樣:

  1. 使用者在瀏覽器輸入網址,或點擊連結。
  2. 請求發到你的伺服器。
  3. 伺服器在回傳頁面之前,會先經過 Middleware。
    1. 所以 Middleware 會在伺服器端執行。
  4. Middleware 可以選擇:
    1. 直接放人進去
    2. 改路線(rewriteredirect)。
    3. 直接回應(回傳 JSON 或錯誤碼)。

為什麼要用 Middleware?

因為它很適合處理所有人都要先經過的規則,像是:

  • 檢查有沒有登入(Auth)。
  • 自動判斷語系(i18n)。
  • 分流測試(A/B Test)。
  • 防止爬蟲或惡意攻擊。
  • 幫 API 統一加上安全標頭(CORS、CSP)。
  • ... 等等

如何在 Next.js 中使用 Middleware?

1. 建立 Middleware 檔案

專案根目錄(或 src/ 根目錄)新增一個檔案,名稱固定要叫:middleware.js

更新:在 Next 16,middleware 被改名叫做 proxy,所以檔案名稱要叫 proxy.js

2. 寫下最簡單的 Middleware

下面是一個最小可行範例:

// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

export function middleware(request: NextRequest) {
  // 只要有人訪問網站,就自動導向 /home
  return NextResponse.redirect(new URL('/home', request.url))
}

解釋:

  • NextRequest = 使用者送進來的請求(像顧客走到門口)。
  • NextResponse = 你要回給使用者的回應(像店員指引方向)。
  • redirect = 直接告訴使用者「請去別的路徑」。

3. 限制 Middleware 的作用範圍

通常你不希望所有頁面都被 Middleware 攔住。

這時可以加一個 matcher,告訴 Next.js 哪些路徑要套用:

export const config = {
  matcher: '/about/:path*', // 只在 /about 以及子路徑生效
}

這就好比跟守門員說:「只有進 VIP 包廂的人,你才需要檢查;一般座位不用理會。」

4. 跑起來

啟動開發伺服器:

npm run dev

當你打開 http://localhost:3000/about,就會看到 Middleware 生效,幫你導去 /home 頁面。

Middleware 實戰範例 - 權限管理

假設你的網站有一個會員專區 /dashboard,規則是:

  • 如果使用者沒登入,就導去 /login
  • 如果已經登入,就放行。

Step 1: 建立 middleware.ts

// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

export function middleware(request: NextRequest) {
  // 嘗試讀取 Cookie(假設裡面會有 token)
  const token = request.cookies.get('token')?.value

  const isDashBoardRoute = request.nextUrl.pathname.startsWith('/dashboard')
  // 如果沒有 token,代表沒登入
  if (!token &&isDashBoardRoute) {
    return NextResponse.redirect(new URL('/login', request.url))
  }

  // 其他情況就放行
  returnNextResponse.next()
}

Step 2: 限制作用範圍(可選)

除了在 middleware 用 request.nextUrl.pathname.startsWith('/dashboard') 判斷以外,也可以在 middleware.js 中用 config 判斷

這樣可以只有在 /dashboard 路徑時,才會執行 middleware:

export const config = {
  matcher: '/dashboard/:path*',
}

Step 3: 實際效果

  • 當使用者直接輸入 /dashboard,但沒登入,Middleware 會「在頁面顯示前」就把他導去 /login
  • 如果有 token,Middleware 就不干涉,正常進入 /dashboard

小總結

  1. Middleware 可以讀取 請求資訊(這裡是 Cookie)。
  2. Middleware 可以決定要 放行導去其他頁面
  3. 你可以透過 matcher 控制它要作用在哪些路徑。

Middleware 實戰範例 2 - 多國語系

第二個範例,我希望:

  • 如果使用者的瀏覽器設定是中文,就帶去 /zh
  • 如果是英文,就帶去 /en
  • 如果不確定,就預設 /en

Step 1: 建立 middleware.ts

// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

export function middleware(request: NextRequest) {
  const { pathname } = request.nextUrl

  // 如果路徑已經有語系,就不處理
  if (pathname.startsWith('/en') || pathname.startsWith('/zh')) {
    returnNextResponse.next()
  }

  // 讀取瀏覽器的 accept-language header
  const lang = request.headers.get('accept-language') || ''
  const isChinese = lang.toLowerCase().startsWith('zh')

  // 建立要導向的網址
  const url = request.nextUrl.clone()
  url.pathname = isChinese ? `/zh${pathname}` : `/en${pathname}`

  return NextResponse.redirect(url)
}

Step 2: 限制作用範圍

只對主要頁面生效,不攔截 API 或靜態資源:

export const config = {
  matcher: '/((?!api|_next/static|_next/image|favicon.ico).*)',
}

Step 3: 實際效果

  • 使用者開網站首頁 /
    • 如果瀏覽器語言是中文,就自動導向 /zh
    • 如果是英文,就自動導向 /en
  • 如果他直接進 /zh/about,因為路徑已經有語系前綴,Middleware 會放行,不會重複導向。

總結

Middleware 是在使用者進入網站前就會先執行的伺服端邏輯,用來決定請求是否放行、轉向或直接回應。

常見用途包含登入檢查、語系自動導向、安全設定與流量分流等等。

在 Next 中,我們也可以透過 matcher 可控制作用範圍。

參考連結:

你可能會感興趣的文章 👇