透過 100+ 個秘訣學習 Nuxt!

middleware

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

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() 參數,且重新導向或路由取消由從中介層傳回值來處理

可能的傳回值為

  • 無任何返回值 (簡單的 return 或沒有 return) - 不會阻止導航,並將移動到下一個中介層函式(如果有的話),或完成路由導航
  • return navigateTo('/') - 重新導向到給定路徑,如果重新導向發生在伺服器端,則會將重新導向代碼設定為 302 Found
  • return navigateTo('/', { redirectCode: 301 }) - 重新導向到給定路徑,如果重新導向發生在伺服器端,則會將重新導向代碼設定為 301 Moved Permanently
  • return abortNavigation() - 停止當前導航
  • return abortNavigation(error) - 拒絕當前導航並顯示錯誤
文件 > API > Utils > Navigate To 中閱讀更多內容。
文件 > API > Utils > Abort Navigation 中閱讀更多內容。
我們建議使用上面的輔助函式來執行重新導向或停止導航。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 路由中介層。

文件 > 範例 > 路由 > 中介層 中閱讀和編輯即時範例。

在建置時設定中介層

您可以於 pages:extend 鉤子中新增具名路由中介層,而無需在每個頁面上使用 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
)
} } })