Bootstrap

解决 vue-router 报错Error: Redirected when going from “/XXX“ to “/XXX“ via a navigation guard.

报错场景:

页面切换试会出现,比如点击左侧菜单导航切换页面时,页面跳转刷新页面时,控制台没有保存信息,有可能是被刷掉了。

具体报错信息如下:


原因分析:

百度翻译:错误:通过导航保护从“/XXX”转到“/XXX”时重定向。

怀疑是切换页面时,路由守卫里处理一些逻辑时,重定向多次了,某些地方没有next() return等。

这个错误可能发生的常见情况是,当在Vue Router中使用导航守卫(比如beforeEachbeforeResolve),并且在其中一个守卫内部触发了对不同路由的重定向。

所以仔细检查路由守卫的逻辑:

//仅看涉及的逻辑

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. 条件1满足时会发生重定向到一个路径。
  2. 条件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比较好解决,要么是路由表错误导致页面找不到正确的路径去跳转,目前我就遇到过这两种情况,当然也有可能是页面内部的重定向导致(很少)。

;