Nuxt.js路由中间件 #

一、中间件概述 #

路由中间件是在导航到特定路由之前运行的函数,可以用于:

  • 身份验证
  • 权限检查
  • 日志记录
  • 重定向
  • 数据预加载

二、创建中间件 #

2.1 匿名中间件 #

直接在页面中定义:

vue
<script setup lang="ts">
definePageMeta({
  middleware: [
    (to, from) => {
      console.log('导航到:', to.path)
    }
  ]
})
</script>

2.2 命名中间件 #

middleware/ 目录下创建:

middleware/auth.ts

typescript
export default defineNuxtRouteMiddleware((to, from) => {
  const isAuthenticated = useState('authenticated')
  
  if (!isAuthenticated.value) {
    return navigateTo('/login')
  }
})

2.3 全局中间件 #

在文件名后添加 .global 后缀:

middleware/auth.global.ts

typescript
export default defineNuxtRouteMiddleware((to, from) => {
  console.log('全局中间件:', to.path)
})

全局中间件会在每次路由导航时自动执行。

三、使用中间件 #

3.1 单个中间件 #

vue
<script setup lang="ts">
definePageMeta({
  middleware: 'auth'
})
</script>

3.2 多个中间件 #

vue
<script setup lang="ts">
definePageMeta({
  middleware: ['auth', 'admin']
})
</script>

3.3 中间件执行顺序 #

  1. 全局中间件(按字母顺序)
  2. 页面定义的中间件(按数组顺序)

四、中间件参数 #

4.1 to和from对象 #

typescript
export default defineNuxtRouteMiddleware((to, from) => {
  console.log('目标路由:', to.path)
  console.log('来源路由:', from?.path)
  console.log('路由参数:', to.params)
  console.log('查询参数:', to.query)
  console.log('路由元信息:', to.meta)
})

4.2 to对象属性 #

属性 说明
path 路由路径
params 路由参数
query 查询参数
hash URL hash
meta 路由元信息
name 路由名称
matched 匹配的路由记录

五、中间件返回值 #

5.1 阻止导航 #

返回 navigateTo 重定向:

typescript
export default defineNuxtRouteMiddleware((to, from) => {
  return navigateTo('/login')
})

5.2 带参数重定向 #

typescript
export default defineNuxtRouteMiddleware((to, from) => {
  return navigateTo({
    path: '/login',
    query: {
      redirect: to.fullPath
    }
  })
})

5.3 外部重定向 #

typescript
export default defineNuxtRouteMiddleware((to, from) => {
  return navigateTo('https://example.com', {
    external: true
  })
})

5.4 抛出错误 #

typescript
export default defineNuxtRouteMiddleware((to, from) => {
  throw createError({
    statusCode: 403,
    message: '没有访问权限'
  })
})

5.5 放行导航 #

不返回任何值或返回 undefined

typescript
export default defineNuxtRouteMiddleware((to, from) => {
  // 验证通过,放行
})

六、常见中间件场景 #

6.1 身份验证中间件 #

middleware/auth.ts

typescript
export default defineNuxtRouteMiddleware((to, from) => {
  const { isAuthenticated } = useAuth()
  
  if (!isAuthenticated.value) {
    return navigateTo({
      path: '/login',
      query: { redirect: to.fullPath }
    })
  }
})

composables/useAuth.ts

typescript
export const useAuth = () => {
  const user = useState('user', () => null)
  const token = useCookie('token')
  
  const isAuthenticated = computed(() => !!token.value && !!user.value)
  
  const login = async (credentials: { email: string; password: string }) => {
    const { data } = await useFetch('/api/auth/login', {
      method: 'POST',
      body: credentials
    })
    
    if (data.value) {
      user.value = data.value.user
      token.value = data.value.token
    }
  }
  
  const logout = async () => {
    await useFetch('/api/auth/logout')
    user.value = null
    token.value = null
  }
  
  return {
    user,
    token,
    isAuthenticated,
    login,
    logout
  }
}

6.2 角色权限中间件 #

middleware/admin.ts

typescript
export default defineNuxtRouteMiddleware((to, from) => {
  const { user } = useAuth()
  
  if (user.value?.role !== 'admin') {
    throw createError({
      statusCode: 403,
      message: '需要管理员权限'
    })
  }
})

使用:

vue
<script setup lang="ts">
definePageMeta({
  middleware: ['auth', 'admin']
})
</script>

6.3 日志中间件 #

middleware/logger.global.ts

typescript
export default defineNuxtRouteMiddleware((to, from) => {
  console.log(`[${new Date().toISOString()}] ${from?.path} → ${to.path}`)
})

6.4 维护模式中间件 #

middleware/maintenance.global.ts

typescript
export default defineNuxtRouteMiddleware((to, from) => {
  const config = useRuntimeConfig()
  
  if (config.public.maintenanceMode && to.path !== '/maintenance') {
    return navigateTo('/maintenance')
  }
})

6.5 语言检测中间件 #

middleware/i18n.global.ts

typescript
export default defineNuxtRouteMiddleware((to, from) => {
  const { locale, setLocale } = useI18n()
  const savedLocale = useCookie('locale')
  
  if (savedLocale.value && savedLocale.value !== locale.value) {
    setLocale(savedLocale.value)
  }
})

七、中间件与路由元信息 #

7.1 定义元信息 #

vue
<script setup lang="ts">
definePageMeta({
  middleware: 'auth',
  meta: {
    requiresAuth: true,
    roles: ['admin', 'editor']
  }
})
</script>

7.2 在中间件中访问元信息 #

typescript
export default defineNuxtRouteMiddleware((to, from) => {
  const { user } = useAuth()
  
  if (to.meta.requiresAuth && !user.value) {
    return navigateTo('/login')
  }
  
  const requiredRoles = to.meta.roles as string[] | undefined
  if (requiredRoles && !requiredRoles.includes(user.value?.role)) {
    throw createError({
      statusCode: 403,
      message: '权限不足'
    })
  }
})

八、中间件最佳实践 #

8.1 组合中间件 #

创建可复用的中间件组合:

middleware/combined.ts

typescript
export default defineNuxtRouteMiddleware(async (to, from) => {
  const authResult = await authMiddleware(to, from)
  if (authResult) return authResult
  
  const roleResult = await roleMiddleware(to, from)
  if (roleResult) return roleResult
})

async function authMiddleware(to, from) {
  const { isAuthenticated } = useAuth()
  if (!isAuthenticated.value) {
    return navigateTo('/login')
  }
}

async function roleMiddleware(to, from) {
  const { user } = useAuth()
  const requiredRoles = to.meta.roles as string[] | undefined
  
  if (requiredRoles && !requiredRoles.includes(user.value?.role)) {
    throw createError({ statusCode: 403 })
  }
}

8.2 条件执行 #

typescript
export default defineNuxtRouteMiddleware((to, from) => {
  if (import.meta.client) {
    // 仅在客户端执行
  }
  
  if (import.meta.server) {
    // 仅在服务端执行
  }
})

8.3 异步操作 #

typescript
export default defineNuxtRouteMiddleware(async (to, from) => {
  const { data } = await useFetch('/api/check-permission', {
    query: { path: to.path }
  })
  
  if (!data.value?.allowed) {
    return navigateTo('/forbidden')
  }
})

九、调试中间件 #

9.1 开发模式日志 #

typescript
export default defineNuxtRouteMiddleware((to, from) => {
  if (process.dev) {
    console.group('中间件执行')
    console.log('目标:', to.path)
    console.log('来源:', from?.path)
    console.log('参数:', to.params)
    console.groupEnd()
  }
})

9.2 使用DevTools #

Nuxt DevTools 可以查看中间件执行情况。

十、完整示例 #

10.1 完整认证系统 #

middleware/auth.ts

typescript
export default defineNuxtRouteMiddleware((to, from) => {
  const { isAuthenticated, user } = useAuth()
  const token = useCookie('token')
  
  if (!token.value) {
    return navigateTo({
      path: '/login',
      query: { redirect: to.fullPath }
    })
  }
  
  if (!user.value) {
    return navigateTo({
      path: '/login',
      query: { redirect: to.fullPath }
    })
  }
  
  const requiredRoles = to.meta.roles as string[] | undefined
  if (requiredRoles && !requiredRoles.includes(user.value.role)) {
    throw createError({
      statusCode: 403,
      message: '您没有访问此页面的权限'
    })
  }
})

pages/admin/index.vue

vue
<script setup lang="ts">
definePageMeta({
  middleware: 'auth',
  meta: {
    roles: ['admin']
  }
})
</script>

<template>
  <div>
    <h1>管理后台</h1>
  </div>
</template>

十一、总结 #

本章介绍了 Nuxt.js 路由中间件:

  • 创建命名中间件和全局中间件
  • 使用 navigateTo 进行重定向
  • 实现身份验证和权限控制
  • 结合路由元信息进行灵活控制
  • 中间件的最佳实践

中间件是构建安全、可控应用的重要工具,下一章我们将学习路由守卫。

最后更新:2026-03-28