导航守卫“无限死循环”是因 beforeEach 中无条件调用 next('/login'),导致跳转反复触发、调用栈溢出;修复需确保每次守卫有且仅有一次 next 调用,并加路径判断防自循环。

导航守卫的“无限死循环”不是浏览器真的卡死,而是 Vue Router 的导航流程在 beforeEach 中反复触发、无法确认完成,最终导致页面停留、URL 不变、组件不渲染,甚至报错 RangeError: Maximum call stack size exceeded。根本原因在于 next() 被错误地无条件调用,让一次跳转不断催生新的跳转,形成自我嵌套。
死循环是怎么发生的
当你写 next('/login') 却没加判断时,当前导航立即中断,并发起一次新导航(to.path 变为 '/login');而这次新导航又会再次进入同一个 beforeEach 守卫——如果逻辑不变,就会再次执行 next('/login'),如此往复。
- 第一次访问
/user→ 守卫检测未登录 →next('/login') - 第二次触发守卫(目标已是
/login)→ 再次执行next('/login') - 第三次、第四次……调用栈持续增长,直到超出浏览器限制
如何快速定位是否是守卫卡住
出现以下现象,大概率是守卫中 next() 没被正确调用:
- 点击菜单或输入 URL 后,页面长时间空白,Vue 组件完全没渲染(
#app内无子节点) - 地址栏 URL 没变化,控制台没有任何报错,网络请求也未发出
- 刷新后能进,但通过内部跳转就卡住
- 开启
console.time日志发现守卫函数执行了多次却始终没打印 “end” 类日志
修复的关键三原则
每次守卫执行,都必须确保:有且仅有一次 next 调用,所有分支都覆盖,跳转目标要防自循环。
-
加路径守门:重定向前先判断
if (to.path !== '/login'),已在登录页就直接next() -
拒绝漏调用:
if/else、try/catch、异步 await 后,每个出口都要有next()、next(false)或next('/xxx') -
避免二次触发:用
next({ path: '/login', replace: true })替换历史,防止用户点返回又回到空页或重复守卫
一个安全的登录校验模板
可直接参考使用:
<!-- 判断是否需要登录,且不在登录页才跳 -->
router.beforeEach(async (to, from, next) => {
const token = localStorage.getItem('token');
if (to.meta.needAuth && !token) {
if (to.path !== '/login') {
next({ path: '/login', replace: true });
} else {
next(); // 已在登录页,放行
}
} else {
next(); // 其他情况一律放行
}
});


















