深入理解 Nuxt.js 中 `middleware` (中间件) 的执行顺序和作用域。

各位靓仔靓女,晚上好!我是你们的老朋友,今天咱们聊聊 Nuxt.js 里让人又爱又恨的 middleware(中间件)。

这玩意儿,说它简单吧,几行代码就能搞定;说它复杂吧,一不留神执行顺序就乱了套,权限验证直接失效,用户体验瞬间爆炸。所以,今天咱们就来好好扒一扒它的底裤,看看它到底是怎么工作的。

开场白:中间件是啥?能吃吗?

简单来说,中间件就像你家门卫大爷,每个请求都要经过他老人家过一遍。他可以检查你有没有带钥匙,是不是业主,有没有携带危险物品等等。Nuxt.js 的中间件就是干这些活儿的,可以在请求到达你的页面组件之前,或者渲染页面之前,做一些预处理。

中间件的种类:五花八门,总有一款适合你

Nuxt.js 提供了几种不同类型的中间件,它们的作用域和执行时机各不相同。咱们先来盘点一下:

  1. 全局中间件 (plugins/)

    • 位置: plugins/ 目录下的 .js.ts 文件。
    • 作用域:整个应用。每个路由都会执行。
    • 特点:需要在 nuxt.config.jsplugins 数组中注册。
    • 用途:比如:全局的权限检查,统计分析,第三方库初始化等等。
  2. 路由中间件 (middleware/)

    • 位置: middleware/ 目录下。
    • 作用域:可以用于特定路由或者页面组件。
    • 特点:需要在 nuxt.config.jsrouter.middleware 对象中注册 (命名路由中间件)。也可以直接在页面组件中使用 (匿名路由中间件)。
    • 用途:权限验证,根据路由参数进行数据预取等等。
  3. 页面中间件 (在页面组件内定义)

    • 位置:直接在 *.vue 页面组件的 middleware 属性中定义。
    • 作用域:只对当前页面组件有效。
    • 特点:最简单直接,但复用性较差。
    • 用途:只对当前页面有效的特殊处理。
  4. 布局中间件 (在布局组件内定义)

    • 位置:直接在 layouts/*.vue 布局组件的 middleware 属性中定义。
    • 作用域:只对使用该布局的页面组件有效。
    • 特点:可以用于布局级别的权限控制或者数据预取。
    • 用途:特定布局下的权限验证或数据获取。

执行顺序:不按套路出牌?

这才是 middleware 最让人头疼的地方!如果你不了解它的执行顺序,很容易就会踩坑。

一般来说,middleware 的执行顺序如下(从上到下,先执行的在上面):

  1. nuxt.config.js 中的 modules (模块) 执行的中间件。(模块可以注册全局中间件)
  2. layouts/*.vue 中定义的 布局中间件 (Layout Middleware)
  3. *.vue 页面组件中定义的 页面中间件 (Page Middleware)
  4. middleware/ 目录下的 命名路由中间件 (Named Route Middleware)。通过 nuxt.config.jsrouter.middleware 注册,并在 *.vue 组件中通过 middleware: 'middleware-name' 使用。
  5. middleware/ 目录下的 匿名路由中间件 (Anonymous Route Middleware)。在 *.vue 组件中直接使用 middleware: [function(){}]
  6. 全局中间件 (Global Middleware)。plugins/ 目录下的 .js.ts 文件,需要在 nuxt.config.jsplugins 数组中注册。

注意:

  • 同类型的中间件,按照其定义顺序执行。
  • 如果多个页面使用同一个布局,布局中间件只会执行一次。
  • 如果路由匹配到多个页面组件,每个页面组件的中间件都会执行。

代码示例:用代码说话,胜过千言万语

咱们来写几个例子,看看 middleware 到底是怎么跑的。

1. 全局中间件 (plugins/auth.js)

// plugins/auth.js
export default function ({ store, redirect, route }) {
  if (route.path !== '/login' && !store.state.auth.loggedIn) {
    console.log('全局中间件:未登录,跳转到登录页');
    return redirect('/login');
  }
}
// nuxt.config.js
export default {
  plugins: [
    '~/plugins/auth' // 注册全局中间件
  ]
}

这个中间件会检查用户是否登录,如果未登录,并且访问的不是登录页,则跳转到登录页。

2. 路由中间件 (middleware/admin.js)

// middleware/admin.js
export default function ({ store, redirect }) {
  if (!store.state.auth.user.isAdmin) {
    console.log('路由中间件:不是管理员,禁止访问');
    return redirect('/');
  }
}
// nuxt.config.js
export default {
  router: {
    middleware: ['auth'] // 注册 auth 中间件
  }
}

这个中间件会检查用户是否是管理员,如果不是,则跳转到首页。

3. 页面中间件 (pages/admin/index.vue)

<template>
  <div>
    <h1>Admin Page</h1>
  </div>
</template>

<script>
export default {
  middleware: ['admin'], // 使用 admin 路由中间件
  mounted() {
    console.log('页面组件:Admin Page mounted');
  }
}
</script>

这个页面组件使用了 admin 路由中间件,只有管理员才能访问。

4. 匿名路由中间件 (pages/secret.vue)

<template>
  <div>
    <h1>Secret Page</h1>
  </div>
</template>

<script>
export default {
  middleware: [
    function ({ store, redirect }) {
      if (!store.state.auth.hasSecret) {
        console.log('匿名路由中间件:没有权限访问');
        return redirect('/');
      }
    }
  ],
  mounted() {
    console.log('页面组件:Secret Page mounted');
  }
}
</script>

这个页面组件使用了匿名路由中间件,只有拥有 secret 权限的用户才能访问。

5. 布局中间件 (layouts/default.vue)

<template>
  <div>
    <Nuxt />
  </div>
</template>

<script>
export default {
  middleware: [
    function ({ store, redirect }) {
      if (store.state.auth.isBanned) {
        console.log('布局中间件:用户被封禁,禁止访问');
        return redirect('/banned');
      }
    }
  ]
}
</script>

这个布局中间件会检查用户是否被封禁,如果是,则跳转到 /banned 页面。所有使用 default 布局的页面都会受到这个中间件的影响。

作用域:你的地盘你做主

middleware 的作用域非常重要。它决定了哪些页面会受到中间件的影响。

  • 全局中间件:影响整个应用,所有路由都会执行。
  • 路由中间件:影响指定的路由或者页面组件。
  • 页面中间件:只影响当前页面组件。
  • 布局中间件:影响所有使用该布局的页面组件。

常见坑点:避坑指南,保你平安

  1. 执行顺序混乱:一定要搞清楚不同类型中间件的执行顺序,避免出现权限验证失效等问题。
  2. 异步操作middleware 函数必须返回 Promise 或者使用 async/await 处理异步操作,否则可能会导致程序出错。
  3. 过度使用:不要滥用 middleware,只在必要的时候才使用。过多的 middleware 会影响性能。
  4. 循环重定向:避免出现循环重定向的情况,比如 A 页面重定向到 B 页面,B 页面又重定向到 A 页面。

进阶技巧:让你的中间件更上一层楼

  1. 使用 async/await:使用 async/await 可以让你的 middleware 代码更加简洁易懂。
  2. 使用 try/catch:使用 try/catch 可以捕获 middleware 中出现的错误,避免程序崩溃。
  3. 使用 storemiddleware 可以访问 store,可以根据 store 中的数据进行判断。
  4. 使用 routemiddleware 可以访问 route,可以根据路由参数进行判断。
  5. 使用 context 对象middleware 函数接收一个 context 对象,包含了 storerouteredirectapp 等属性,可以方便地访问 Nuxt.js 的各种功能。

表格总结:一图胜千言

中间件类型 位置 作用域 执行时机 如何使用 适用场景
全局中间件 plugins/ 整个应用 每个路由 plugins/ 目录下创建 .js.ts 文件,并在 nuxt.config.jsplugins 数组中注册。 全局的权限检查,统计分析,第三方库初始化等。
路由中间件 middleware/ 特定路由或页面组件 路由匹配到页面组件之前 middleware/ 目录下创建 .js.ts 文件,并在 nuxt.config.jsrouter.middleware 对象中注册 (命名路由中间件)。也可以直接在页面组件中使用 middleware: [function(){}] (匿名路由中间件)。 权限验证,根据路由参数进行数据预取等。
页面中间件 *.vue 页面组件内 当前页面组件 页面组件渲染之前 *.vue 页面组件的 middleware 属性中定义。 只对当前页面有效的特殊处理。
布局中间件 layouts/*.vue 布局组件内 使用该布局的页面组件 页面组件使用该布局时渲染之前 layouts/*.vue 布局组件的 middleware 属性中定义。 特定布局下的权限验证或数据获取。

总结:掌握中间件,走向人生巅峰

middleware 是 Nuxt.js 中非常重要的一个概念,掌握它可以让你更好地控制应用的流程,实现更复杂的功能。希望今天的讲解能够帮助你更好地理解 middleware 的执行顺序和作用域,避开常见的坑点,写出更健壮、更高效的 Nuxt.js 应用。

最后,记住一点:多写代码,多调试,才能真正掌握 middleware 的精髓!

散会!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注