vue-router 4.0 动态路由会跳转到 404 页面的问题

news2024/11/13 9:42:57

引子

开发过前端单页面应用的小伙伴们,应该对前端路由都不陌生吧。

无论是用 vue 或者 react,都有官方提供的 router 方案。

但是有些场景下,处于安全性和友好性考虑,我们需要用到动态路由。

如果你不知道什么叫动态路由,可以想一想下面的场景。

比如现在我们的项目中有一些页面,只有 vip 用户能看到,普通用户不能看到,那么我们怎么做呢?

我们首先的做法肯定是,将该页面的入口隐藏掉。但是如果仅仅只是这样做,还不够,那只是假隐藏,因为用户仍然可以通过直接输入链接的方式来访问到该页面。

正确的做法应该是:首先隐藏掉入口;其次根据用户的权限,动态的生成对应的路由

这篇文章主要是想分享下,最近使用 vue-router 4.0 版本过程中,由于用到了动态路由引起的一些问题,以及个人研究出来的解决方案。

为了清楚的描述我们的问题,现在假设我们有两个这样的页面:

那么我们就会对应着两个不同的路由:

[
	{ path: '/home', name: 'home', component: Home },
	{ path: '/vip', name: 'vip', component: Vip }
]

当然为了简化业务模型,这里,我们只用了两个路由。分别对应着两个页面,一个是所有用户都能看到的主页 home;一个是登录了的用户才能看到的 vip 页面。

当然在实际的业务逻辑中,肯定是需要登录、注册等页面,这里假设这些操作我们都能在 home 页面内完成。

如果不需要根据用户来区分的话,我们直接像下面这样生成对应的路由即可:

const router = createRouter({
	history: createWebHistory(import.meta.env.BASE_URL),
	scrollBehavior: () => ({ y: 0 }),
	routes: [
		// 重定向到 /home 路径
		{ path: '/', redirect: "/home", },
		{ path: '/home', name: 'home', component: Home },
		{ path: '/vip', name: 'vip', component: Vip },
		// 404 页面
		{
		    path: "/404",
		    name: "NotFound",
		    component: () => import("@views/404.vue"),
		    hidden: true,
		    meta: { title: "404" },
		},
		// 当什么都没有匹配到的时候,重定向页面到 404 页面
		{ path: "/:pathMatch(.*)", redirect: "/404", name: "notMatch", hidden: true },
	],
})

但是如果现在的需求是需要我们来动态的区分,我们应该怎么做呢?

动态路由

我们先来了解下,如何实现动态路由。

如果你没有用过 vue-router 的动态路由,可以先参考下 vue-router 的官方文档:

Dynamic Routing | Vue Router

根据文档里所写,想要动态的添加、删除路由,直接通过下面的方式即可:

// 增加 route
router.addRoute({ path: '/home', name: 'home', component: Home })

// 删除 route
router.removeRoute('home')

初窥门径

所以,我们可以稍微改造下我们之前的代码:

// router.js
const router = createRouter({
	history: createWebHistory(import.meta.env.BASE_URL),
	scrollBehavior: () => ({ y: 0 }),
	routes: [
		// 重定向到 /home 路径
		{ path: '/', redirect: "/home", },
		{ path: '/home', name: 'home', component: Home },
		// 404 页面
		{
		    path: "/404",
		    name: "NotFound",
		    component: () => import("@views/404.vue"),
		    hidden: true,
		    meta: { title: "404" },
		},
		// 当什么都没有匹配到的时候,重定向页面到 404 页面
		{ path: "/:pathMatch(.*)", redirect: "/404", name: "notMatch", hidden: true },
	],
})

export default router;

// api.js
export const login = async () => {
	// 执行登录操作
	let res = await dologin();

	if (res.sucess) {
		await storeUserInfo(res);
		// 登录成功,动态的添加 vip 路由
		router.addRoute({ path: '/vip', name: 'vip', component: Vip });
	}
}

// permission.js
router.beforeEach(async (to, from, next) => {
	// 如果存在用户信息
	if (await getUserInfo()) {
		// 如果 vip 这个 router 没有初始化,那么动态的增加 vip 路由
		if (!router.hasRoute("vip")) {
			router.addRoute({ path: '/vip', name: 'vip', component: Vip });
		}
    }
	next();
});

router.afterEach((to) => {
  // 在导航被确认后,调用 afterEach 钩子,执行一些操作
  doSomething();
});

经过改造之后,我们在初始化的时候,没有加入 vip 路由,那么你即使直接通过 https://example.com/vip 链接也无法访问到该页面,会被最后的 notMatch 路由匹配到,最后被重定向到 404 页面。

关于 noMatch 路由的用法,不了解的小伙伴,可以参考下 vue-router 官方文档:Dynamic Route Matching with Params | Vue Router。他的作用是,确保当路由没有匹配到的时候,永远能正确的将页面导航到 404 页面。

当用户在我们 home 页面执行登录操作,登录成功后,保存用户信息,并且动态的添加 vip 路由。

当然,仅仅只是在登录的时候动态新增路由,还不够。

为了用户体验的友好性,我们不可能让用户每次用我们的页面的时候,都先执行一遍登录。

所以,我们就会借用,router 提供的一些列的生命周期函数,来帮助我们确保,当用户信息存在的时候,能自动添加我们的动态路由。

如果你不了解 router 的生命周期的话,可以参考下这个页面:Navigation Guards | Vue Router

beforeEach 方法内,我们每次通过 getUserInfo 方法拿用户的信息。当我们识别到存在用户信息后,就需要判断路由 vip 是否存在,当不存在的时候,动态的创建该路由。

可以说,整个流程下来,是很清晰明了的,逻辑也很通畅。

棘手的问题

如果没有经验的小伙伴,也许看不出来,上面的代码会出现什么问题。

设想下,用户在实际使用我们的系统的时候,可能会通过几种场景进入我们的 vip 页面。

一种场景是,当用户未登录,这时候,也没有 vip 这个路由的存在,那么路由匹配不到,会直接被 noMatch 捕获,然后再进一步重定向到 404 页面。

也就是说,这种未登录的场景下,会被跳转到 404 页面。当然为了用户让用户体验更友好,这时候,其实我们应该先提醒用户登录,登录成功后再激活路由跳转。如果这时候,用户不想登录,那么我们可以直接拒绝用户的跳转需求。

另外一种场景是,当用户已经登陆过了,这时候他点击 vip 路由,想要跳转。这时候,借助我们上面改造过的代码,直接跳转到 vip 页面,不存在任何的问题。

但是还有第三种使用场景是,用户不通过我们的 home 页面进入 vip 页面,他直接在浏览器上输入链接 https://example.com/vip,想一步到位,直接进入我们的 vip 页面。

这第三种使用场景下面,也会分为两种子情景。当用户未登录,自然是拿不到用户信息,也没有 vip 路由,自然会被 noMatch 捕获到,最后重定向到 404 页面;当用户已经登录,系统也存在用户信息,我们通过 getUserInfo 方法也能拿到用户的信息,然后也会进一步成功的动态创建 vip 路由,这时候,你在实际使用的时候,还是会发现,我们仍旧被重定向到了 404 页面了。

这第三种情况下的第二种子情景,就是我们这篇文章想要解决的问题。

我们理想中使用过程中的流程是下面这样的:

但是却走不通,是为什么呢?

原来真实的流程是下面这样的:

image.png

解决方案

了解了实际的流程走向后,我们就知道该怎么解决这个问题了。

我们可以在动态增加了 vip 路由后,再直接把用户重定向到 vip 页面就行了。

整个流程就会变成下面这样:

理清了思路以后,我们就可以着手来改造我们的代码了。

// permission.js
router.beforeEach(async (to, from, next) => {
	// 如果存在用户信息
	if (await getUserInfo()) {
		// 如果 vip 这个 router 没有初始化,那么动态的增加 vip 路由
		if (!router.hasRoute("vip")) {
			router.addRoute({ path: '/vip', name: 'vip', component: Vip });
		}

		// 如果当前路由目标是 /404,且来自 /vip
		if (to.name === "NotFound" && to.redirectedFrom?.path === "/vip") {
			// 重定向到 /vip 路由
			next({
				path: to.redirectedFrom.path,
				query: to.redirectedFrom.query,
				replace: true,
			});
			return;
		}
    }
    
	next();
});

我们在添加完 vip 路由以后,可以判断,当前想要加载的路由是否为 404,如果是,并且是由 /vip 跳转而来,则再重定向回去即可。

当然以上的代码只适用于我们文章一开始假设的场景,真实的业务场景中,应该会有更多更复杂的情况,但是万变不离其宗,只要理清了思路,掌握了原理,找到了应对方案,再复杂的场景也能一步步抽丝剥茧,应付起来将会游刃有余。

后记

个人习惯,每次写完一篇技术文章,总想总结点啥,因此都会写个后记。

看起来可能会像是“无病呻吟”,所以,要是不感兴趣的小伙伴可以直接略过即可。

虽然本文中的脉络很清晰,给人感觉好像轻车熟路,能够轻易地药到病除的感觉。但是在实际碰到这个问题的过程中,远没有现在写的这么轻松。

现在总结的时候,可以看作是开了上帝视角,一下子就抓住关键点。但是当你身处漩涡中心的时候,你就是局中人,你是很难跳脱开来,精准定位问题所在的。

不过我挺认同一个观点的,从解决 bug 的能力就能看出一个程序员的水平。

不存在没有 bug 的程序,甚至于有些问题其实就是无解的。大多数情况先,我们能做的也只不过是在权衡利弊的情况下,找到一种最佳的解决方案而已。

共勉之!愿天下没有难解决的 bug!


本文首发自今日头条:https://www.toutiao.com/article/7252565650931991101/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/736769.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

翻遍整个牛客网,整理出了全网最全的Java面试八股文大合集,整整4000多页

大家从 Boss 直聘上或者其他招聘网站上都可以看到 Java 岗位众多,Java 岗位的招聘薪酬天差地别,人才要求也是五花八门。而很多 Java 工程师求职过程中,也是冷暖自知。很多时候技术有,但是面试的时候就是过不了! 为了帮…

4.7 x64dbg 应用层的钩子扫描

所谓的应用层钩子(Application-level hooks)是一种编程技术,它允许应用程序通过在特定事件发生时执行特定代码来自定义或扩展其行为。这些事件可以是用户交互,系统事件,或者其他应用程序内部的事件。应用层钩子是在应用…

【Zabbix 监控 Windows 系统,Java应用,SNMP】

目录 一、Zabbix 监控 Windows 系统1、下载 Windows 客户端 Zabbix agent 22、安装客户端,配置3、在服务端 Web 页面添加主机,关联模板 二、Zabbix 监控 java 应用1、客户端开启 java jmxremote 远程监控功能1、配置 java jmxremote 远程监控功能2、启动…

【ARM Coresight 系列文章 3.1 - ARM Coresight DP 对 AP 的访问 2】

文章目录 图 1-1 如上图1-1 所示,DAP上可以集成多个MEM-AP,上图是集成了3个MEM-AP,它们可能是AXI-AP, AHB-AP, APB-AP。 那么AP的类型是如何区分的呢? 不同的组件会使用不同MEM-AP接口,如Cortex-A/Coretex-R 系列的c…

ai绘画工具有哪些?这几款好用的ai绘画工具免费分享给你

上周,我去了一家现代艺术画廊,墙上挂满了令人叹为观止的绘画作品。我被其中一幅细腻而充满情感的油画所深深吸引,想要了解背后的创作过程。这时,一位热情的艺术导师走到我身边。她微笑着说:“这幅作品实际上是由ai绘画…

解决“_mkdir无法识别空格目录“问题

在C编程里,有时候需要创建一个文件夹,通常使用库函数_mkdir(const char* dirname)来新建一个文件夹,该库函数每次只能创建一个文件夹,不能级联创建。若要级联创建文件,则请用递归方式或者for循环方式调用_mkdir()。 #…

7月6日华为云盘古气象大模型登上《Nature》杂志:相比传统数值预报快10000倍

7月6日,国际顶级学术期刊《自然》(Nature)杂志正刊发表了华为云盘古大模型研发团队的最新研究成果——《三维神经网络用于精准中期全球天气预报》(《Accurate medium-range global weather forecasting with 3D neural networks》…

CrossKD 原理与代码解析

paper:CrossKD: Cross-Head Knowledge Distillation for Dense Object Detection official implementation: https://github.com/jbwang1997/CrossKD 前言 蒸馏可以分为预测蒸馏prediction mimicking和特征蒸馏feature imitation两种,201…

【LeetCode】HOT 100(26)

题单介绍: 精选 100 道力扣(LeetCode)上最热门的题目,适合初识算法与数据结构的新手和想要在短时间内高效提升的人,熟练掌握这 100 道题,你就已经具备了在代码世界通行的基本能力。 目录 题单介绍&#…

什么是 AOP?对于 Spring IoC 和 AOP 的理解?Spring AOP 和 AspectJ AOP 有什么区别?

什么是 AOP? AOP(Aspect-Oriented Programming),即 面向切面编程, 它与OOP( ObjectOriented Programming, 面向对象编程) 相辅相成,提供了与OOP 不同的抽象软件结构的视角 在 OOP 中, 我们以类(class)作为我们的基本单元 而 A…

Zynq 多个UDP客户端组网启动问题(Auto negotiation error)PS:附UDP客户端初始化代码

最近正在进行一个Zynq项目,根据设计需求,需要将上位机作为UDP服务器,而FPGA则充当UDP客户端。同时,服务器需要能够接收和控制多个UDP客户端。 开发过程中,我是基于lwip UDP Perf Client 官方模版开发的。我遇到了以下几…

重磅!高通大客户「跳单」,智能座舱SoC赛道进入「混战期」

哪家车企是高通座舱芯片的最大客户?答案不是蔚来、理想、小鹏等智能化布局领先的新势力,而是比亚迪。 高工智能汽车研究院监测数据显示,2022年中国市场(不含进出口)乘用车智能座舱前装标配高通芯片交付367.45万辆&…

DALL·E2(unCLIP)、Stable Diffusion、IS、FID要点总结

DALLE 1 DALLE 1可以看成是VQ-VAE和文本经过BPE编码得到的embedding AE(Auto Encoder) encoder decoder结构,AE在生成任务时只会模仿不会创造,所有有了后面的VAE VAE(Variational AutoEncoder) 不再学习固定的bottleneck特征…

2023-07-07-liunx环境,python调用ITK(c++版本)批量生成Drr

文章目录 一、前言二、配置过程2.1.CMake与ITK的配置2.2.改写ITK的生成drr代码2.3.编译代码2.4.python调用cpp 三、总结四、参考博客 一、前言 最近在做配准,需要用ITK来生成数据,windows版本可以通过cmake与visual studio可以跑通生成。但是想要在linu…

纯干货,全文手码:如何利用低/无代码平台建立集团信息化系统

信息化系统是企业管理体系的延伸 对于一家集团企业而言,要实现信息化,首先需要考虑是否已经建立了完备的信息化管理制度。早在上世纪九十年代卡特彼勒引入了6 Sigma,使整个集团公司的运营规范化、系统化。通过多年的实践积累,卡特…

【雕爷学编程】Arduino动手做(157)---MX1508双路电机驱动模块

37款传感器与执行器的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是不止这37种的。鉴于本人手头积累了一些传感器和执行器模块,依照实践出真知(一定要动手做)的理念,以学习和交流为目的&am…

计算机视觉:通过边缘检测探究卷积的特征提取功能

本文重点 在前面的课程中,我们学习了卷积核的运算,同时我们也学习了卷积核的含义,我们可以将卷积核理解为特征提取器,也就是说一个卷积核就是一个特征提取器,很多人对这种说法不了解,下面我们就通过一个边缘检测的例子来看一下卷积核是如何进行边缘特征的提取的。 什么…

[ICML 2023] Fast inference from transformers via speculative decoding

Contents IntroductionSpeculative DecodingStandardized SamplingSpeculative Sampling AnalysisNumber of Generated TokensCalculating α \alpha αWalltime ImprovementNumber of Arithmetic OperationsChoosing γ \gamma γ ExperimentsReferences Introduction 为了…

springboot+vue膳食营养健康网站零食美食品商城_4d8g9

随着社会的不断进步与发展,人们对生活质量要求逐步提升。如果开发一款膳食营养健康网站,可以让用户在最短的时间里享受到最好的服务;而开发本网站,又能够提高网站整体工作水平,简化工作程序,这对管理员和用…

北京“数据二十条”发布,筑牢数据安全根基,加速释放数据产能

要实现2000亿的目标,基础保障如何做好? 7月5日,中共北京市委、北京市人民政府印发《关于更好发挥数据要素作用进一步加快发展数字经济的实施意见》(《实施意见》分为9个部分,共涉及20项具体任务,也被称作“…