middleware
Nuxt 提供中间件以在导航到特定路由之前运行代码。
Nuxt 提供了一个可自定义的 路由中间件 框架,您可以在整个应用程序中使用它,非常适合提取要在导航到特定路由之前运行的代码。
有三种路由中间件:
- 匿名(或内联)路由中间件直接在页面中定义。
- 命名路由中间件,放置在
middleware/
中,并在页面上使用时通过异步导入自动加载。 - 全局路由中间件,放置在
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 提供了两个全局可用的辅助函数,可以直接从中间件返回。
navigateTo
- 重定向到给定路由abortNavigation
- 中止导航,带有可选的错误消息。
与来自 vue-router
的 导航守卫 不同,不传递第三个 next()
参数,并且重定向或路由取消通过从中间件返回值来处理。
可能的返回值是:
- 无返回值(简单的
return
或没有 return)- 不会阻止导航,并将移动到下一个中间件函数(如果有),或完成路由导航 return navigateTo('/')
- 重定向到给定的路径,如果重定向发生在服务器端,则将重定向代码设置为302
Foundreturn navigateTo('/', { redirectCode: 301 })
- 重定向到给定的路径,如果重定向发生在服务器端,则将重定向代码设置为301
Moved Permanentlyreturn abortNavigation()
- 停止当前导航return abortNavigation(error)
- 使用错误拒绝当前导航
我们建议使用上面的辅助函数来执行重定向或停止导航。 vue-router 文档 中描述的其他可能的返回值可能有效,但未来可能会有破坏性更改。
中间件顺序
中间件按以下顺序运行:
- 全局中间件
- 页面定义的中间件顺序(如果使用数组语法声明了多个中间件)
例如,假设您有以下中间件和组件:
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>
您可以预期中间件将按以下顺序运行:
analytics.global.ts
setup.global.ts
- 自定义内联中间件
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
路由中间件。
在 文档 > 示例 > 路由 > 中间件 中阅读和编辑实时示例。
在构建时设置中间件
除了在每个页面上使用 definePageMeta
之外,你还可以在 pages:extend
钩子中添加命名路由中间件。
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)
}
}
})