它的主要任务是:在进入页面之前执行代码。
常见的应用场景包括:
- 权限验证:检查用户是否登录,没登录就踢回登录页。
- 路由守卫:比如 VIP 视频页面,非会员禁止进入。
- 埋点统计:记录用户从哪个页面跳到了哪个页面。
- 动态重定向:比如根据用户的语言偏好,自动跳转到
/zh或/en。
Nuxt 提供了三种灵活的配置方式:
| 类型 | 文件位置 | 影响范围 | 场景举例 |
|---|---|---|---|
| 全局 (Global) | middleware/*.global.ts |
所有页面跳转都会触发 | 统计所有页面的访问量 |
| 命名 (Named) | middleware/auth.ts |
只有指定的页面才会触发 | 仅在“个人中心”开启登录检查 |
| 匿名 (Inline) | 写在pages/*.vue 里 |
仅该当前页面有效 | 某个特定页面的临时逻辑 |
生命周期?
中间件运行的时机非常关键。它发生在路由匹配之后,渲染页面之前。
- 首次访问(SSR):你在浏览器输入网址回车,中间件在服务器上运行。
- 后续跳转(SPA):你在页面点击
<NuxtLink>,中间件在浏览器中运行。
命名中间件
创建middleware/auth.ts
export default defineNuxtRouteMiddleware((to, from) => {
const isLoggedIn = false // 模拟登录状态获取逻辑
// 如果要去管理页且没登录
if (to.path.startsWith('/admin') && !isLoggedIn) {
// 强制跳转到登录页
return navigateTo('/login')
}
})
在需要保护的页面里调用
<script setup>
definePageMeta({
middleware: 'auth' // 告诉 Nuxt:进这个页面前,先让 auth 保安查一下
})
</script>
全局中间件
注意名字要包含global
比如auth.global.ts
export default defineNuxtRouteMiddleware((to, from) => {
console.log("全局中间件", to.path)
return
})
一般我们会在全局中间件里面判断用户有没有登录,如果没有登录就直接跳转到登录页面
之前前后端分离的情况下,用户的登录状态是存在pinia里面的,但是在nuxtjs中,我们需要这样做
- 先将token存入cookie
// 在 login.vue 或 auth store 中
const token = useCookie('auth-token', {
maxAge: 60 * 60 * 24 * 7, // 有效期 7 天
})
token.value = 'your-server-token' // 写入后,浏览器和服务器都能读取
- 在pinia中同步状态
// stores/auth.ts
export const useAuthStore = defineStore('auth', () => {
const token = useCookie('auth-token')
const isLoggedIn = computed(() => !!token.value)
return { token, isLoggedIn }
})
- 在全局中间件里面判断
export default defineNuxtRouteMiddleware((to, from) => {
const authStore = useAuthStore() // 这里的 Pinia 会自动读取上面的 Cookie
// 白名单:如果是去登录页,直接放行,防止死循环
if (to.path === '/login') {
return
}
// 判断是否登录
if (!authStore.isLoggedIn) {
// 没登录,重定向到登录页
return navigateTo('/login')
}
})
匿名中间件
既然有了全局和命名中间件,为什么还要用匿名的?通常用于以下场景:
- “仅此一家”的逻辑:某个逻辑只在这一特定页面有用,且永远不会被其他页面复用。
- 临时快速拦截:比如一个特殊的营销活动页,只在特定时间内需要一个简单的校验,没必要去
middleware/目录增加文件负担。 - 强耦合逻辑:逻辑与该页面的业务紧密相关,放在一起更方便维护。
<script setup>
definePageMeta({
// 这里的匿名函数就是一个中间件
middleware: [
function (to, from) {
const config = useRuntimeConfig()
const isEventEnded = true // 假设这是从某处获取的逻辑
if (isEventEnded) {
// 如果活动结束,禁止进入该页面,直接回首页
console.log('匿名中间件拦截:活动已结束')
return navigateTo('/')
}
},
// 你甚至可以同时混合使用“命名中间件”
'auth'
]
})
</script>
<template>
<div>
<h1>超级限时活动页</h1>
</div>
</template>