中间件目录 middleware

Nuxt 提供中间件来在导航到特定路由之前运行代码。

Nuxt 提供了一个可定制的路由中间件框架,您可以在整个应用程序中使用它,非常适合在导航到特定路由之前提取要运行的代码。

路由中间件在 Nuxt 应用程序的 Vue 部分中运行。 尽管名称相似,但它们与服务器中间件完全不同,服务器中间件在应用程序的 Nitro 服务器部分运行。

路由中间件分为三种:

  1. 匿名(或内联)路由中间件,在使用它们的页面中直接定义。
  2. 具名路由中间件,放置在middleware/目录下,在页面使用时会异步导入自动加载。(注意:路由中间件名称被标准化为kebab-case也叫连字符命名法,所以 someMiddleware 变成了 some-middleware。)
  3. 全局路由中间件,放置在middleware/目录下(后缀为.global),每次路由变化时自动运行。

前两种路由中间件可以definePageMeta中定义

参考格式

路由中间件是接收当前路由和下一个路由作为参数的导航守卫。

js
export default defineNuxtRouteMiddleware((to, from) => {
  if (to.params.id === '1')
    return abortNavigation()

  // 在真实的应用程序中,您可能不会将每个路由重定向到 `/`
  // 但是,在重定向之前检查 `to.path` 很重要,或者您
  // 可能会出现无限重定向循环
  if (to.path !== '/')
    return navigateTo('/')
})

Nuxt 提供了两个全局可用的助手,可以直接从中间件返回:

  1. navigateTo (to: RouteLocationRaw | undefined | null, options?: { replace: boolean, redirectCode: number, external: boolean ) - 在插件或中间件内重定向到给定的路由。 也可以直接调用它来进行页面导航。
  2. abortNavigation (err?: string | Error) - 中止导航,带有可选的错误消息。

vue-router 文档 中的导航守卫不同,不传递第三个 next() 参数 ,重定向或路由取消是通过从中间件返回一个值来处理的。 可能的返回值是:

  • nothing - 不阻塞导航并且将移动到下一个中间件函数,如果有的话,或者完成路由导航
  • return navigateTo('/')return navigateTo({ path: '/' }) - 重定向到给定路径并将重定向代码设置为 302 Found 如果重定向发生在服务器端
  • return navigateTo('/', { redirectCode: 301 }) - 重定向到给定路径并将重定向代码设置为 301 永久移动 如果重定向发生在服务器端
  • return abortNavigation() - 停止当前导航
  • return abortNavigation(error) - 拒绝错误的当前导航

我们建议使用上面的辅助函数来执行重定向或停止导航。 vue-router 文档 中描述的其他可能的返回值可能有效,但将来可能会有重大变化。

中间件的运行顺序

中间件按以下顺序运行:

  1. 全局中间件
  2. 页面定义中间件顺序(如果有多个中间件用数组语法声明)

例如,假设您有以下中间件和组件:

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

您可以期望中间件按以下顺序运行:

  1. analytics.global.ts
  2. setup.global.ts
  3. Custom inline middleware
  4. auth.ts

全局中间件的排序

默认情况下,全局中间件根据文件名按字母顺序执行。

但是,有时您可能想要定义一个特定的顺序。 例如,在最后一个场景中,setup.global.ts 可能需要在 analytics.global.ts 之前运行。 在这种情况下,我们建议在全局中间件前加上字母编号。

middleware/ directory
middleware/
--| 01.setup.global.ts
--| 02.analytics.global.ts
--| auth.ts

示例中的可以理解为字符串,而不是数字
如果您不熟悉字母编号,请记住文件名是按字符串而不是数值排序的。 例如,10.new.global.ts 会出现在 2.new.global.ts 之前。 这就是为什么该示例在单个数字前面加上“0”的原因。

中间件何时运行

如果您的站点是服务器呈现或生成的,则初始页面的中间件将在页面呈现时执行,然后在客户端再次执行。 如果您的中间件需要浏览器环境,例如您有一个生成的站点、主动缓存响应或想要从本地存储读取值,则可能需要这样做。

但是,如果您想避免这种行为,您可以这样做:

js
export default defineNuxtRouteMiddleware((to) => {
  // 跳过服务器上的中间件
  if (process.server)
    return
  // 完全跳过客户端的中间件
  if (process.client)
    return
  // 或者只在初始客户端加载时跳过中间件
  const nuxtApp = useNuxtApp()
  if (process.client && nuxtApp.isHydrating && nuxtApp.payload.serverRendered)
    return
})

动态添加中间件

可以使用 addRouteMiddleware() 辅助函数手动添加全局或命名路由中间件,例如从插件中。

ts
export default defineNuxtPlugin(() => {
  addRouteMiddleware('global-test', () => {
    console.log('这个全局中间件被添加到一个插件中,并将在每次路由更改时运行')
  }, { global: true })

  addRouteMiddleware('named-test', () => {
    console.log('这个命名的中间件被添加到一个插件中,并将覆盖任何现有的同名中间件')
  })
})

命名路由中间件示例:

bash
-| middleware/
---| auth.ts

在你的页面文件中,你可以引用这个路由中间件

vue
<script setup>
definePageMeta({
  middleware: ['auth']
  // or middleware: 'auth'
})
</script>

现在,在该页面的导航完成之前,将运行auth路由中间件。