报错场景:
页面切换试会出现,比如点击左侧菜单导航切换页面时,页面跳转刷新页面时,控制台没有保存信息,有可能是被刷掉了。
具体报错信息如下:
原因分析:
百度翻译:错误:通过导航保护从“/XXX”转到“/XXX”时重定向。
怀疑是切换页面时,路由守卫里处理一些逻辑时,重定向多次了,某些地方没有next() return等。
这个错误可能发生的常见情况是,当在Vue Router中使用导航守卫(比如beforeEach
或beforeResolve
),并且在其中一个守卫内部触发了对不同路由的重定向。
所以仔细检查路由守卫的逻辑:
//仅看涉及的逻辑
router.beforeEach((to, from, next) => {
const token = getToken()
// 判断权限
if (没有权限) { // 去401页
next({ name: "401" })
} else { // 有权限
// 一些配置
if (token) { //已登录
if (条件1) {
next({ path: `/**` })
} else if (条件2) {
next({ path: `/***` })
} else {
next()
}
}
if (to.name.startsWith("index") || to.name.startsWith("home")) { //不需要权限和是否登录
next()
} else {
if (token && to.name === 'login') {
// 已登录且要跳转的页面是登录页
next({
name: 'home', // 跳转到home页
})
} else if (!token && to.name !== 'login') {
// 未登录,要跳转的页面不是登录页
next({
name: 'login', // 跳转到登录页
query: {
redirect: to.path,
},
})
} else {
if (!token) {
next() // 进入登录页
return
}
store.dispatch("getUserInfo").then(user => {
//已登录,且密码已超时,先去修改密码页
if(已超时){
if (to.name === 'resetPassword') {
next()
return
}
next({
name: 'resetPassword' // 跳转到重置密码页
})
return
}
else if(to.name === 'resetPassword'){
next({
name: 'home', // 跳转到home页
})
return
}else{
next()
}
})
}
}
}
})
发现后半段逻辑有点问题,关于是否有token的逻辑判断的地方,写的比较弯弯绕绕,仔细查看后,发现是由于有些页面,不需要权限,所以避开了,错误问题应该于此无关。
可能还是因为多个if判断导致的问题,详细打印信息来解决。
解决过程:
方法:避免冗余导航,先删除不必要的导航,排查哪里出错。
//仅看涉及的逻辑
router.beforeEach((to, from, next) => {
const token = getToken()
// 判断权限
if (没有权限) { // 去401页
next({ name: "401" })
} else { // 有权限
// 一些配置
if (token) { //已登录
if (条件1) {
console.log("有token条件1");
next({ path: `/**` })
} else if (条件2) {
console.log("有token条件2");
next({ path: `/***` })
} else {
console.log("有token但是没有判断条件");
next()
}
}
// 删除下方的home和login的跳转逻辑
console.log("最后条件");
next()
}
})
报错依旧出现,应该是上面的多个条件判断导致的。
并且发现:点击条件1和条件2 的页面时,有报错。
点击两次条件1和条件2的页面,再点击一次不满足于条件1和2 的页面,三次点击的控制台打印信息:
分析一下情况:
根据打印信息,有两个条件会导致重定向:
- 条件1满足时会发生重定向到一个路径。
- 条件2满足时也会发生重定向到另一个路径。
在这两种情况下,都执行了next()
,因此在执行了一次重定向后,又执行了一次next()
,导致了重定向错误。
需要确保在发生重定向时不再继续执行后续的next()
。使用return
语句来确保在条件满足时立即退出函数,而不继续执行其他的next()
。
所以改成下面这种:
//仅看涉及的逻辑
router.beforeEach((to, from, next) => {
const token = getToken()
// 判断权限
if (没有权限) { // 去401页
next({ name: "401" })
} else { // 有权限
// 一些配置
if (token) { //已登录
if (条件1) {
console.log("有token条件1");
next({ path: `/**` })
return
} else if (条件2) {
console.log("有token条件2");
next({ path: `/***` })
return
} else {
console.log("有token但是没有判断条件");
next()
return
}
}
// 删除下方的home和login的跳转逻辑
console.log("最后条件");
next()
return
}
})
但是点击页面依旧有报错,打印信息少了一条
说明最底下的return没有走到,在第二次的时候return生效了。
可是其他地方依旧有报错,说明不是这个路由守卫的问题,或许系统里有其他问题导致。
系统里并没有其他地方使用路由守卫,于是决定去排查路由表的问题。
发现路由表中,页面的path:
然而跳转的path是有一个前缀的,这个前缀是由于系统用于区分不同的环境,所以添加的前缀,也就是在路由守卫的条件1里判断的内容。
所以是由于前缀导致的!。。。。。
这样就没有报错了!
解决方案:
路由表缺少前缀,于是在每一个路由的path里添加前缀。
但是由于系统的路由表过于长,有快一千行代码,里面有各种逻辑,陈年老旧的判断等等,话了一两个小时来查看这部分逻辑,并没有太大的进展,因为不止是路由表没有前缀的问题,页面的url已经有了前缀,所以导致是哪部分给url加了前缀变得更扑朔迷离了。。。
暂且如此,剩下的就是根据项目来修改代码了。
像这类重定向的问题,要么是判断分支导致的多次重定向,这时加return比较好解决,要么是路由表错误导致页面找不到正确的路径去跳转,目前我就遇到过这两种情况,当然也有可能是页面内部的重定向导致(很少)。