NUXT3学习日记四(路由中间件、导航守卫)

前言

Nuxt 3 中,中间件(Middleware)是用于在页面渲染之前或导航发生之前执行的函数。它们允许你在路由切换时执行逻辑,像是身份验证、重定向、权限控制、数据预加载等任务。中间件可以被全局使用,也可以只在特定页面或布局中使用。

中间件必须在文件夹middleware中,在这个middleware文件夹中创建js文件

中间件的作用

  • 身份验证:用于检查用户是否登录或是否有权限访问某些页面。
  • 重定向:根据条件自动重定向用户到另一个页面。
  • 条件加载数据:在路由切换前加载或检查数据。
  • 页面控制:控制哪些页面可以访问,哪些不能。
  • 日志记录:记录访问的路径、时间等信息。

普通中间件

以下就是一个中间件代码:

javascript 复制代码
middleware/my.js

export default defineNuxtRouteMiddleware((to, from) => {
    console.log(to.path)
    if (to.path === '/about') {
        console.log('www');
        //必须加return,否则不能跳转
        return navigateTo('/login')
        //返回true这放行,后面的中间件也会执行
        // return true
    }
})

在这段代码中,to是去哪,from是从哪里来。

另外这里提醒一下,拦截跳转路由记得需要加上return,否则跳转不起作用。

在vue文件中使用中间件,两种方式,一种是单独提出来在middleware文件夹中定义中间件,另外一种就是在vue文件中直接定义。

这里我推荐官方的第一种,在middleware文件夹中定义中间件:

javascript 复制代码
//about.vue

<template>
  <div>
    
  </div>
</template>

<script setup>
definePageMeta({
  /**
   * 路由中间件1
   */
  middleware:[
    'my'
  ]
  /*************************************************/
  /**
   * 路由中间件2
   */
  // middleware:[
  //   function(to,from){
  //     console.log(to.path);
  //   }
  // ]
});
</script>

<style scoped>
</style>

注意!!! 这里middleware是个数组,在middleware文件夹中定义的js文件名字就是数组的元素。

例如:

那么有多个中间件,执行顺序是什么样的呢?

这里就按照数组中元素的顺序执行中间件

下面来验证一下

我们修改一下my.js中的代码:

javascript 复制代码
export default defineNuxtRouteMiddleware((to, from) => {
    console.log(to.path)
    if (to.path === '/about') {
        //返回true这放行,后面的中间件也会执行
        return true
    }
})

这里如果想要让后续的中间件起作用,我们需要return一个true。

这里如果return的是false,服务端渲染就会返回404。

my_two.js中的代码:

javascript 复制代码
export default defineNuxtRouteMiddleware((to, from) => {
    console.log(to.path)
    if (to.path === '/about') {
        //必须加return,否则不能跳转
        return navigateTo('/login')
    }
})

下面请看输出结果:

可以看出先执行my.js中的代码,然后执行my_two.js中的代码。

全局中间件

注意,全局中间件的文件名必须以'global.js'结尾,例如test.global.js文件。

我们的全局中间件直接编写不用我们自己去引入就可以起作用。

如果middleware文件夹中有多个全局中间件,根据文件名ascll(阿斯克码)从小到大排序执行。

javascript 复制代码
//全局中间件,拦截所有的请求,所以在about.vue中先输出"/about",
//跳转到login.vue中输出"/login"

//如果有多个全局中间件,根据ascll(阿斯克码)从小到大排序执行
export default defineNuxtRouteMiddleware((to, from) => {
    console.log(to.path)
    if (to.path === '/about') {
        return navigateTo('/login')
    }
})

输出结果为:

这里呢,我们首先跳转到about页面,被全局中间件进行拦截,紧接着进入到login页面再次被拦截,所以先输出/about再输出/login。

全局路由守卫

此时在客户端跳转没有问题,在服务端渲染报500错误,因为服务端没有token或ElMessage。

在之后会使用pinia进行解决,本章先看其他办法。

javascript 复制代码
//全局中间件,拦截所有的请求,所以在about.vue中先输出"/about",
//跳转到login.vue中输出"/login"

//如果有多个全局中间件,根据ascll(阿斯克码)从小到大排序执行
export default defineNuxtRouteMiddleware((to, from) => {

    /**
     * 路由守卫
     */

    //此时访问客户端正常执行
    //直接访问服务端,报500错误,因为没有token
    let passURL = ['/','/login','/about','/index']
    if (!passURL.includes(to.path)) {
        let token = localStorage.getItem('token')
        if (!token) {
            ElMessage.error('请先登录')
            return navigateTo('/login')
        }
    }
})

不知道大家有没有发现,我们nuxt3是先去执行一下服务端而后执行客户端代码,所以我们需要给上面代码加一个判断。如下所示:

javascript 复制代码
//全局中间件,拦截所有的请求,所以在about.vue中先输出"/about",
//跳转到login.vue中输出"/login"

//如果有多个全局中间件,根据ascll(阿斯克码)从小到大排序执行
export default defineNuxtRouteMiddleware((to, from) => {
    /**
     * 路由守卫
     */
    let passURL = ['/','/login','/about','/index']
    if (!passURL.includes(to.path)) {
        let token = ''
        if (import.meta.client) {
            token = localStorage.getItem('token')
        }
        if (!token) {
            return navigateTo('/login')
        }
    }
})

这样无论去访问路由地址(服务端渲染),还是在客户端点击进行跳转,都会成功执行代码,实现路由守卫。但是这样就没有用户提示了,体验感很差,您请往下看。

javascript 复制代码
//全局中间件,拦截所有的请求,所以在about.vue中先输出"/about",
//跳转到login.vue中输出"/login"

//如果有多个全局中间件,根据ascll(阿斯克码)从小到大排序执行
export default defineNuxtRouteMiddleware((to, from) => {

    /**
     * 路由守卫
     */

    //此时访问客户端正常执行
    //直接访问服务端,报500错误,因为没有token
    let passURL = ['/','/login','/about','/index']
    if (!passURL.includes(to.path)) {
        let token = ''
        if (import.meta.client) {
            token = localStorage.getItem('token')
        }
        if (!token) {
            return navigateTo({
                path:'/login',
                query:{
                    code:401,
                    message:'没有token,请先登录'
                }
            })
        }
    }
})
javascript 复制代码
<template>
  <div>
    <p>登录页面</p>
  </div>
</template>

<script setup>
onMounted(() => {
  const route = useRoute();
  if (route.query.code) {
    ElMessage.error(route.query.code + "" + route.query.message);
  }
});
</script>

<style scoped>
</style>

得到的效果如下所示:

相关推荐
埋头编程~42 分钟前
【C++】踏上C++学习之旅(十):深入“类和对象“世界,掌握编程黄金法则(五)(最终篇,内含初始化列表、静态成员、友元以及内部类等等)
java·c++·学习
飞凌嵌入式3 小时前
飞凌嵌入式旗下教育品牌ElfBoard与西安科技大学共建「科教融合基地」
嵌入式硬件·学习·嵌入式·飞凌嵌入式
Red Red9 小时前
网安基础知识|IDS入侵检测系统|IPS入侵防御系统|堡垒机|VPN|EDR|CC防御|云安全-VDC/VPC|安全服务
网络·笔记·学习·安全·web安全
Natural_yz10 小时前
大数据学习17之Spark-Core
大数据·学习·spark
qq_1728055911 小时前
RUST学习教程-安装教程
开发语言·学习·rust·安装
一只小小汤圆11 小时前
opencascade源码学习之BRepOffsetAPI包 -BRepOffsetAPI_DraftAngle
c++·学习·opencascade
虾球xz11 小时前
游戏引擎学习第20天
前端·学习·游戏引擎
LateBloomer77711 小时前
FreeRTOS——信号量
笔记·stm32·学习·freertos
legend_jz11 小时前
【Linux】线程控制
linux·服务器·开发语言·c++·笔记·学习·学习方法