中间件
约 1035 字大约 3 分钟
2026-01-29
重要
路由中间件(Route Middleware)用于在页面导航前执行逻辑,常见用途:
- 登录校验 / 权限控制
- 按条件重定向(如未登录跳转登录页)
- 阻止非法访问并中断导航
- 统一埋点或导航日志
最佳实践
- 中间件保持轻量:只做 "是否允许进入页面" 的判断,不做重请求
- 避免副作用:中间件可能在 SSR + CSR 各执行一次,副作用逻辑要加环境判断
- 只用
to/from:在中间件里优先使用参数,不要依赖useRoute()当前上下文 - 命名清晰:
auth、admin这类语义化命名更易维护 - 有顺序要求就显式控制:全局中间件用前缀(如
01.)保证执行顺序
核心概念
defineNuxtRouteMiddleware
Nuxt 路由中间件通过 defineNuxtRouteMiddleware 定义,函数签名如下:
export default defineNuxtRouteMiddleware((to, from) => {
// to: 目标路由
// from: 来源路由
})其中最重要的一点是,中间件 "返回什么"
- 返回
navigateTo(): 重定向目标页面 - 返回
abortNavigation(): 终止本次导航 - 返回
abortNavigation(error): 中止并抛出错误 - 返回
undefined/null/ 不写return:放行,进入下一个中间件或页面
app/middleware/auth.ts
export default defineNuxtRouteMiddleware((to, from) => {
const token = useCookie<string | null>('token')
// 未登录:重定向
if (!token.value) {
return navigateTo('/login')
}
// 返回空值:放行
return
})匿名路由中间件(Inline)
匿名中间件通常直接写在页面 definePageMeta 里,仅作用于当前页面
app/pages/profile.vue
<script setup lang="ts">
definePageMeta({
middleware: [
(to, from) => {
// 仅这个页面生效
if (!to.query.tab) {
return navigateTo('/profile?tab=base')
}
},
],
})
</script>命名路由中间件(Named)
在 app/middleware 中创建文件(如 auth.ts),然后在页面中按名称引用。它们只有在页面或布局中显式声明时才会执行
app/middleware/auth.ts
export default defineNuxtRouteMiddleware(() => {
const token = useCookie<string | null>('token')
if (!token.value) {
return navigateTo('/login')
}
})app/pages/account.vue
<script setup lang="ts">
definePageMeta({
middleware: 'auth',
// 也可以是数组:middleware: ['auth', 'admin']
})
</script>全局路由中间件(Global)
文件名带 .global.ts 会在每次路由导航时执行
app/middleware/01.logger.global.ts
export default defineNuxtRouteMiddleware((to, from) => {
console.log('[route]', from.fullPath, '->', to.fullPath)
})注册与执行顺序
自动注册
app/middleware 下的中间件会被 Nuxt 自动注册,常见的文件结构如下
app
middleware
auth.ts
admin.ts
01.logger.global.ts
02.auth.global.ts
执行顺序
- 先执行全局中间件(
.global.ts)常用文件名前缀控制顺序 - 再执行页面中声明的中间件(
definePageMeta({ middleware })) - 同一组内按声明顺序执行
app/pages/admin/index.vue
<script setup lang="ts">
definePageMeta({
// auth 执行完后再执行 admin
middleware: ['auth', 'admin'],
})
</script>动态注册中间件
如果想在插件里 "运行时注册" 中间件,可以用 addRouteMiddleware
app/plugins/route-guard.ts
export default defineNuxtPlugin(() => {
addRouteMiddleware(
'audit',
(to, from) => {
console.log('[audit]', from.fullPath, '->', to.fullPath)
},
{ global: true },
)
})与 server/middleware 的区别
这两者很容易混淆,但职责不同:
app/middleware/*:路由中间件,作用于页面导航(路由层)server/middleware/*:Nitro 服务端中间件,作用于每个 HTTP 请求(服务端请求层)
简单判断:
如果你要做“页面准入控制”(登录态、权限跳转),用 app/middleware;
如果你要做“请求预处理”(请求头、日志、限流等),用 server/middleware。
示例:登录校验 + 管理员权限 + 全局日志
准备目录
app
middleware
01.logger.global.ts
auth.ts
admin.ts
pages
login.vue
admin
index.vue
创建全局日志中间件
app/middleware/01.logger.global.tsexport default defineNuxtRouteMiddleware((to, from) => { // 所有页面跳转都会经过这里 console.log('[middleware]', from.fullPath, '->', to.fullPath) })创建登录中间件
authapp/middleware/auth.tsexport default defineNuxtRouteMiddleware((to) => { const token = useCookie<string | null>('token') // 避免登录页自身重定向死循环 if (!token.value && to.path !== '/login') { return navigateTo('/login') } })创建管理员中间件
adminapp/middleware/admin.tsexport default defineNuxtRouteMiddleware(() => { // 示例:真实项目通常来自 user store / 接口返回 const role = useCookie<'admin' | 'user'>('role') if (role.value !== 'admin') { // 中断导航并给出错误信息 return abortNavigation( createError({ statusCode: 403, statusMessage: '无权限访问该页面', }), ) } })在页面声明中间件
app/pages/admin/index.vue<script setup lang="ts"> definePageMeta({ // 先验证登录,再校验管理员权限 middleware: ['auth', 'admin'], }) </script> <template> <section>Admin Dashboard</section> </template>
