文章目录
有些页面不是谁都能访问的。后台管理只有管理员能进,个人中心需要登录才能看,会员内容要付费才能解锁......这些都是页面访问控制的场景。Nuxt 的中间件系统就是来解决这些问题的。
一、什么是路由守卫
路由守卫就是导航过程中的"关卡":
- 用户点击链接
- 触发路由守卫(关卡检查)
- 检查通过 → 放行
- 检查不通过 → 重定向或拦截
Nuxt 用中间件来实现路由守卫,比 Vue Router 的方式更简洁。
二、定义中间件
中间件放在 middleware 目录。创建一个登录检查中间件:
ts
// middleware/auth.ts
export default defineNuxtRouteMiddleware((to, from) => {
const token = useCookie('token')
// 未登录,跳转到登录页
if (!token.value) {
return navigateTo('/login')
}
})
在页面中使用:
vue
<script setup lang="ts">
definePageMeta({
middleware: 'auth' // 使用 auth 中间件
})
</script>
<template>
<div>
<h1>个人中心</h1>
<p>只有登录用户能看到</p>
</div>
</template>
三、全局中间件
想让中间件对所有页面生效,文件名加 .global 后缀:
ts
// middleware/auth.global.ts
export default defineNuxtRouteMiddleware((to, from) => {
// 所有页面都会经过这里
console.log('导航到:', to.path)
})
典型场景:全局登录状态检查
ts
// middleware/auth.global.ts
export default defineNuxtRouteMiddleware((to, from) => {
const token = useCookie('token')
const publicPages = ['/', '/login', '/register']
// 公开页面直接放行
if (publicPages.includes(to.path)) {
return
}
// 非公开页面需要登录
if (!token.value) {
return navigateTo('/login')
}
})
四、多个中间件
页面可以同时使用多个中间件:
vue
<script setup lang="ts">
definePageMeta({
middleware: [
'auth', // 先检查登录
'admin' // 再检查管理员权限
]
})
</script>
中间件按数组顺序执行,任何一个返回重定向就会中断后续流程。
五、中间件传参
中间件可以接收参数:
ts
// middleware/role.ts
export default defineNuxtRouteMiddleware((to, from) => {
const requiredRole = to.meta.role as string
const userRole = useCookie('role').value
if (requiredRole && userRole !== requiredRole) {
return navigateTo('/403')
}
})
页面中定义需要的角色:
vue
<script setup lang="ts">
definePageMeta({
middleware: 'role',
meta: {
role: 'admin' // 需要管理员角色
}
})
</script>
六、重定向选项
navigateTo 支持多种选项:
ts
// 外部链接
return navigateTo('https://google.com', { external: true })
// 替换历史记录
return navigateTo('/login', { replace: true })
// 新窗口打开
return navigateTo('/report', { open: { target: '_blank' } })
// 保留查询参数
return navigateTo({
path: '/login',
query: { redirect: to.fullPath } // 登录后跳回原页面
})
七、中止导航
不是所有情况都要重定向,有时候只需要中止:
ts
export default defineNuxtRouteMiddleware((to, from) => {
const confirmed = confirm('确定要离开吗?未保存的内容会丢失')
if (!confirmed) {
return abortNavigation() // 中止导航,留在当前页
}
// 返回 undefined 或不返回就是放行
})
还可以传递错误信息:
ts
export default defineNuxtRouteMiddleware((to, from) => {
return abortNavigation(
createError({
statusCode: 403,
message: '您没有权限访问此页面'
})
)
})
八、页面离开确认
表单页面常用,防止用户误操作丢失数据:
ts
// middleware/unsaved-changes.ts
export default defineNuxtRouteMiddleware((to, from) => {
const hasUnsavedChanges = useState('unsavedChanges')
if (hasUnsavedChanges.value) {
const confirmed = confirm('有未保存的更改,确定要离开吗?')
if (!confirmed) {
return abortNavigation()
}
// 确认离开,重置状态
hasUnsavedChanges.value = false
}
})
页面中:
vue
<script setup lang="ts">
const hasUnsavedChanges = useState('unsavedChanges')
// 表单数据变化时
watch(formData, () => {
hasUnsavedChanges.value = true
}, { deep: true })
// 保存成功后
const save = async () => {
await saveForm()
hasUnsavedChanges.value = false
}
definePageMeta({
middleware: 'unsaved-changes'
})
</script>
九、服务端中间件
中间件在 SSR 时也会执行。有些检查需要只在服务端进行:
ts
export default defineNuxtRouteMiddleware(async (to, from) => {
// 只在服务端执行
if (process.server) {
const event = useRequestEvent()
const ip = getRequestIP(event)
// IP 黑名单检查
if (await isBlockedIP(ip)) {
return navigateTo('/blocked')
}
}
})
十、中间件执行顺序
Nuxt 中间件执行顺序:
- 全局中间件(按字母排序)
- 页面定义的中间件(按定义顺序)
- 布局中间件(如果有)
ts
// middleware/01-first.global.ts - 先执行
// middleware/02-second.global.ts - 后执行
十一、调试中间件
开发时可以打印日志:
ts
export default defineNuxtRouteMiddleware((to, from) => {
console.log('From:', from.path)
console.log('To:', to.path)
console.log('Meta:', to.meta)
})
总结
路由守卫核心用法:
| 功能 | 实现方式 |
|---|---|
| 登录检查 | middleware/auth.ts |
| 全局守卫 | 文件名加 .global |
| 多个守卫 | middleware: ['auth', 'admin'] |
| 重定向 | navigateTo('/path') |
| 中止导航 | abortNavigation() |
| 传递错误 | abortNavigation(createError(...)) |
路由守卫是权限控制的基础,下一篇我们聊聊组件进阶------插槽与事件传递。
相关文章
延伸阅读
内容有帮助?点赞、收藏、关注三连!评论区等你 💪