透過超過 100 個技巧的集合學習 Nuxt!

中介層

Nuxt 提供中介層,以便在導航至特定路由之前執行程式碼。

Nuxt 提供一個可自訂的路由中介層架構,您可以在整個應用程式中使用它,非常適合提取您想在導航至特定路由之前執行的程式碼。

路由中介層有三種類型

  1. 匿名(或內聯)路由中介層直接在頁面內定義。
  2. 具名路由中介層,放置在 middleware/ 中,並在頁面上使用時透過非同步匯入自動載入。
  3. 全域路由中介層,放置在 middleware/ 中,並帶有 .global 後綴,並且在每次路由變更時都會執行。

前兩種路由中介層可以在 definePageMeta 中定義。

中介層的名稱會正規化為 kebab-case:myMiddleware 會變成 my-middleware
路由中介層在您的 Nuxt 應用程式的 Vue 部分內執行。儘管名稱相似,它們與在應用程式的 Nitro 伺服器部分中執行的伺服器中介層完全不同。

用法

路由中介層是導航守衛,接收目前的路由和下一個路由作為參數。

middleware/my-middleware.ts
export default 
defineNuxtRouteMiddleware
((
to
,
from
) => {
if (
to
.
params
.
id
=== '1') {
return
abortNavigation
()
} // In a real app you would probably not redirect every route to `/` // however it is important to check `to.path` before redirecting or you // might get an infinite redirect loop if (
to
.
path
!== '/') {
return
navigateTo
('/')
} })

Nuxt 提供兩個全域可用的輔助程式,可以直接從中介層傳回。

  1. navigateTo - 重新導向至給定的路由
  2. abortNavigation - 中止導航,並提供可選的錯誤訊息。

與來自 vue-router導航守衛不同,不會傳遞第三個 next() 參數,而且**重新導向或路由取消由從中介層傳回值來處理**。

可能的傳回值為

  • nothing(簡單的 return 或根本沒有傳回值)- 不會阻止導航,而且會移至下一個中介層函式(如果有的話),或者完成路由導航
  • return navigateTo('/') - 重新導向至給定的路徑,而且如果重新導向發生在伺服器端,則會將重新導向代碼設定為302 找到
  • return navigateTo('/', { redirectCode: 301 }) - 重新導向至給定的路徑,而且如果重新導向發生在伺服器端,則會將重新導向代碼設定為301 永久移動
  • return abortNavigation() - 停止目前的導航
  • return abortNavigation(error) - 以錯誤拒絕目前的導航
請在 文件 > API > 輔助程式 > 導航至 中閱讀更多資訊。
請在 文件 > API > 輔助程式 > 中止導航 中閱讀更多資訊。
我們建議使用上述輔助函式來執行重新導向或停止導航。vue-router 文件中描述的其他可能傳回值可能會運作,但未來可能會發生重大變更。

中介層順序

中介層會依下列順序執行

  1. 全域中介層
  2. 頁面定義的中介層順序(如果使用陣列語法宣告多個中介層)

例如,假設您有下列中介層和元件

middleware/ 目錄
-| middleware/
---| analytics.global.ts
---| setup.global.ts
---| auth.ts
pages/profile.vue
<script setup lang="ts">
definePageMeta({
  middleware: [
    function (to, from) {
      // Custom inline middleware
    },
    'auth',
  ],
});
</script>

您可以預期中介層會依下列順序執行

  1. analytics.global.ts
  2. setup.global.ts
  3. 自訂內聯中介層
  4. auth.ts

排序全域中介層

依預設,全域中介層會根據檔案名稱按字母順序執行。

不過,有時候您可能會想定義特定的順序。例如,在上一個情境中,setup.global.ts 可能需要在 analytics.global.ts 之前執行。在這種情況下,我們建議以「字母」編號為全域中介層加上前綴。

目錄結構
-| middleware/
---| 01.setup.global.ts
---| 02.analytics.global.ts
---| auth.ts
如果您不熟悉「字母」編號,請記住檔案名稱會以字串而非數值排序。例如,10.new.global.ts 會排在 2.new.global.ts 之前。這就是為什麼範例會以 0 為個位數的數字加上前綴。

中介層何時執行

如果您的網站是伺服器渲染或產生的,初始頁面的中介軟體會在頁面渲染時執行一次,然後在客戶端再次執行。如果您的中介軟體需要瀏覽器環境,例如您有一個產生的網站、積極快取回應,或想要從本地儲存讀取值,則可能需要這樣做。

但是,如果您想避免這種行為,您可以這樣做

middleware/example.ts
export default 
defineNuxtRouteMiddleware
(
to
=> {
// skip middleware on server if (import.meta.
server
) return
// skip middleware on client side entirely if (import.meta.
client
) return
// or only skip middleware on initial client load const
nuxtApp
=
useNuxtApp
()
if (import.meta.
client
&&
nuxtApp
.
isHydrating
&&
nuxtApp
.
payload
.
serverRendered
) return
})
渲染錯誤頁面是一個完全獨立的頁面載入,這意味著任何已註冊的中介軟體都會再次執行。您可以使用中介軟體中的 useError 來檢查是否正在處理錯誤。

動態新增中介軟體

可以使用 addRouteMiddleware() 輔助函式手動新增全域或具名的路由中介軟體,例如從外掛程式中新增。

export default 
defineNuxtPlugin
(() => {
addRouteMiddleware
('global-test', () => {
console
.
log
('this global middleware was added in a plugin and will be run on every route change')
}, {
global
: true })
addRouteMiddleware
('named-test', () => {
console
.
log
('this named middleware was added in a plugin and would override any existing middleware of the same name')
}) })

範例

目錄結構
-| middleware/
---| auth.ts

在您的頁面檔案中,您可以參考此路由中介軟體

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

現在,在導覽至該頁面完成之前,將會執行 auth 路由中介軟體。

Docs > Examples > Routing > Middleware 中閱讀並編輯即時範例。

在建置時設定中介軟體

您可以在 pages:extend hook 中新增具名的路由中介軟體,而不是在每個頁面上使用 definePageMeta

nuxt.config.ts
import type { 
NuxtPage
} from 'nuxt/schema'
export default
defineNuxtConfig
({
hooks
: {
'pages:extend' (
pages
) {
function
setMiddleware
(
pages
:
NuxtPage
[]) {
for (const
page
of
pages
) {
if (/* some condition */ true) {
page
.
meta
||= {}
// Note that this will override any middleware set in `definePageMeta` in the page
page
.
meta
.middleware = ['named']
} if (
page
.
children
) {
setMiddleware
(
page
.
children
)
} } }
setMiddleware
(
pages
)
} } })