iT邦幫忙

2023 iThome 鐵人賽

DAY 12
0
Vue.js

Nuxt 3 初學者指南:30天從基礎到實踐系列 第 12

Day 12 – Nuxt 3 Middleware(中介層)

  • 分享至 

  • xImage
  •  

Middleware 就像是你進入一個地方時的入口一樣,可以在存取每個頁面之前執行特定的操作,比如驗證身份、處理資料等,讓我們能夠有效管理應用程式的行為。

使用方式

首先確認 app.vue<NuxtPage /> 元件。

// app.vue
<template>
  <NuxtPage />
</template>

匿名

在頁面中透過 definePageMetamiddleware 設定。

Step 1

建立頁面

pages
 ┣ user.vue           要加入 middleware 的頁面
 ┗ unAuthorized.vue   不符合條件時導向的頁面
// pages/user.vue
<template>
  <h1>I'm {{ $route.query.id }}</h1>
</template>
// pages/unAuthorized.vue
<template>
  <h1>WHO ARE YOU</h1>
</template>

Step 2

在進到 /user 之前,確認 url 要有 id 可以識別身分,如果沒有則導向未授權頁面。

// pages/user.vue
<script setup lang="ts">
definePageMeta({
    middleware: [
        function (to, from) {
            if (to.query.id === undefined) {
                return navigateTo('/UnAuthorized')
            }
        },
    ],
});
</script>

Step 3

執行結果:/user 沒有 id 時,route 會自動導向 /UnAuthorized

具名

檔案建立在 middleware/ ,在頁面中透過 definePageMeta 設定。middleware 名稱為檔案名稱的 kebab-case。

Step 1

在專案目錄底下建立 middleware/ 資料夾,再建立 checkAuth.ts 檔案。

nuxt-project
 ┣ middleware 
 ┃   ┗ checkAuth.ts

Step 2

/middleware/checkAuth.ts 加入以下程式碼。

// middleware/checkAuth.ts
export default defineNuxtRouteMiddleware((to, from) => {
  console.log("middleware in checkAuth.ts");
  //此處加上 middleware 要執行的動作。
});

Step 3

在須執行此 Middleware 的頁面(範例檔案為接續「匿名」的 /pages/user.vue )。

// pages/user.vue
<script setup lang="ts">
definePageMeta({
  middleware: [
    function (to, from) {
      console.log("middleware in user.vue");
      if (to.query.id === undefined) {
        return navigateTo("/UnAuthorized");
      }
    },
    "check-auth",
  ],
});
</script>

Step 4

執行結果,請求 http://127.0.0.1:3000/user?id=1234 時,會執行「匿名」及「具名」的 Middleware。

https://ithelp.ithome.com.tw/upload/images/20230926/20162805zdwxwZLh9m.png

全域

middleware/ 建立檔案設定,名稱須加上 .global 以識別是全域的。
當路徑改變時,都會自動去執行全域的 middleware

Step 1

建立 checkRoute.global.ts 檔案

nuxt-project
 ┣ middleware 
 ┃  ┣ checkAuth.ts
 ┃  ┗ checkRoute.global.ts

Step 2

加入以下程式碼

// middleware/checkRoute.global.ts
export default defineNuxtRouteMiddleware((to, from) => {
  console.log("middleware in checkRoute.global.ts");
  //此處加上全域 middleware 要執行的動作。
});

Step 3

執行結果:存取 http://127.0.0.1:3000/user?id=1234 時,會執行「全域」、「匿名」及「具名」的 Middleware,且「全域」會先被執行。

https://ithelp.ithome.com.tw/upload/images/20230926/20162805sMdSuM3l7C.png

參數說明

  • to(去哪裡) 跟 from(從哪來)提供的參數相同。
    下方為請求 http://127.0.0.1:3000/user?id=1234console.log(to) 的範例。
    值得注意的是 params 代表的是路由:/user/[id];而 query 代表的是路由:user?id=[id]
    https://ithelp.ithome.com.tw/upload/images/20230926/20162805oMLNSfBR3k.png

  • abortNavigation (err?: string | Error):不允許進到此頁面(錯誤代碼 500),參數為錯誤訊息。

    // pages/user.vue
    script setup lang="ts">
    efinePageMeta({
     middleware: [
       function (to, from) {
         abortNavigation("沒權限");
       },
     ],
    );
    /script>
    

    https://ithelp.ithome.com.tw/upload/images/20230926/20162805VdkYAoT8ko.png

  • navigateTo (to: RouteLocationRaw | undefined | null, options?: { replace: boolean, redirectCode: number, external: boolean ):導向其他畫面,參數可指定 url 及其他控制變數。

    此範例為上面「匿名」範例

匿名、具名、全域的執行順序 ?

https://ithelp.ithome.com.tw/upload/images/20230926/20162805nQaoS3c3Si.png

「全域」的一定最優先,且「全域」之間的優先順序是依照檔名。
「匿名」及「具名」則是依據在 definePageMeta 設定的順序決定。

// 可以在全域的檔名前面加上數字來設定先後順序
middleware
 ┣ 01.checkRoute.global.ts
 ┣ 02.analytics.global.ts 
 ┣ checkAuth.ts

Server、Client 是否執行 Middleware

Middleware 可以根據不同處理程序(例如伺服器端和客戶端)控制在特定流程時選擇性跳過。

export default defineNuxtRouteMiddleware(to => {
  // server 不執行
  if (process.server) return
    
  // client 不執行
  if (process.client) return
  
 // client 首次渲染時不執行(重新 reload 頁面也算是首次渲染)
  const nuxtApp = useNuxtApp()
  if (process.client && nuxtApp.isHydrating && nuxtApp.payload.serverRendered) return
})

🌞 Upcoming

今天介紹了 Pages 的 Middleware,明天會介紹 Nuxt 3 Server API 的使用方法,而 Server API 也有 Middleware,兩者有什麼不一樣呢?明日揭曉!


參考資料:

Nuxt 3 Middleware


上一篇
Day 11 – Nuxt 3 Layouts(佈局)
下一篇
Day 13 – Nuxt 3 Server
系列文
Nuxt 3 初學者指南:30天從基礎到實踐30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言