跳到主要內容
前端開發

Nuxt 3 / 4 的 Route Middleware:進頁面前先做判斷

整理 Nuxt 3 與 Nuxt 4 的 Route Middleware,用 defineNuxtRouteMiddleware 在進入頁面前檢查登入狀態,搭配 navigateTo 重新導向,並說明一般 middleware、global middleware 與 definePageMeta 的用法。

W

Nuxt 2 時期就有 Middleware,常拿來在進頁面前做登入驗證。

Middleware 可以先簡單理解成:

使用者準備進入某個頁面之前,先執行一段檢查。

最常見的用途就是登入驗證。

例如:

使用者進入 /member
↓
先檢查有沒有登入
↓
有登入 → 繼續進入
沒登入 → 導到 /login

Nuxt 3 開始使用 defineNuxtRouteMiddleware(),Nuxt 4 也延續相同方式。

建立登入驗證 Middleware

Nuxt 4 建立:

app/middleware/auth.ts

Nuxt 3 則是:

middleware/auth.ts

內容:

export default defineNuxtRouteMiddleware(() => {
  const authState = useAuthState()

  if (!authState.value) {
    return navigateTo('/login')
  }
})

可以白話理解成:

如果沒有登入
→ 不要繼續進原本的頁面
→ 改去 /login

navigateTo() 就是 Nuxt 3 / 4 用來做頁面導向的方式。

在頁面指定 Middleware

不是每一頁都需要登入驗證。

例如只有會員頁需要,可以在頁面裡使用:

<script setup lang="ts">
definePageMeta({
  middleware: 'auth'
})
</script>

這樣進入這個頁面之前,就會先執行:

app/middleware/auth.ts

Nuxt 3 則是:

middleware/auth.ts

搭配頁面的自訂設定

也可以自己在 definePageMeta() 加上設定:

<script setup lang="ts">
definePageMeta({
  middleware: 'auth',
  requiresAuth: true
})
</script>

Middleware 裡就能讀:

export default defineNuxtRouteMiddleware((to) => {
  if (to.meta.requiresAuth) {
    const authState = useAuthState()

    if (!authState.value) {
      return navigateTo('/login')
    }
  }
})

這裡的:

to

代表「準備前往的頁面」。

所以:

to.meta.requiresAuth

就是查看那個頁面有沒有設定:

requiresAuth: true

全站都要執行:.global

如果不想每個頁面都寫:

middleware: 'auth'

可以把檔名改成:

auth.global.ts

Nuxt 4:

app/middleware/auth.global.ts

Nuxt 3:

middleware/auth.global.ts

.global 代表:

每次切換頁面都執行這支 middleware。

例如:

middleware/
├── auth.ts
└── analytics.global.ts

可以理解成:

auth.ts
→ 頁面有指定才執行

analytics.global.ts
→ 每個頁面都執行

如果整個後台都需要登入驗證,也可以考慮使用 global middleware。

注意不要一直重新導向

假設寫成:

export default defineNuxtRouteMiddleware(() => {
  return navigateTo('/login')
})

如果連 /login 本身也會執行這支 middleware,就可能一直重新導向。

因此通常要先判斷:

export default defineNuxtRouteMiddleware((to) => {
  const authState = useAuthState()

  if (
    !authState.value &&
    to.path !== '/login'
  ) {
    return navigateTo('/login')
  }
})

意思就是:

沒有登入
而且現在不是登入頁
→ 才導向 /login

Route Middleware 和 Server Middleware 不一樣

Nuxt 裡其實有兩種名字很像的 middleware。

Route Middleware

Nuxt 4:

app/middleware/

用途範例:

進入頁面前檢查
登入驗證
權限判斷
頁面重新導向

Server Middleware

server/middleware/

用途比較像:

處理 HTTP request
記錄 log
設定 request context
Server 端驗證

兩個不是同一套東西。

如果是:

使用者能不能進這個 Vue 頁面?

通常是在講 Route Middleware。

Nuxt 2、3、4 對照

Nuxt 2Nuxt 3Nuxt 4
Route Middleware 位置middleware/middleware/app/middleware/
Middleware 寫法context functiondefineNuxtRouteMiddleware()defineNuxtRouteMiddleware()
重新導向redirect()navigateTo()navigateTo()
頁面設定Options APIdefinePageMeta()definePageMeta()
全域 Middleware另外設定.global.ts.global.ts
讀取頁面 meta舊 route metato.metato.meta

所以從 Nuxt 3 升到 Nuxt 4:

Middleware 的概念和寫法幾乎沒有變。

主要只是檔案從:

middleware/

搬到:

app/middleware/

小結

可以把 Route Middleware 記成:

進頁面之前,先幫我檢查一下。

例如登入驗證:

export default defineNuxtRouteMiddleware(() => {
  const authState = useAuthState()

  if (!authState.value) {
    return navigateTo('/login')
  }
})

頁面需要使用時:

definePageMeta({
  middleware: 'auth'
})

如果每一頁都要執行,就把檔名改成:

auth.global.ts

Nuxt 3 與 Nuxt 4 的寫法基本相同,最大的差別只是 Nuxt 4 的 Route Middleware 放在:

app/middleware/

參考資料

分享這篇