背景
我们团队一个前端小组使用 Vue.js 进行开发,项目中使用了 vue-router 进行路由管理。在某次项目迭代中,我们新增了一个权限管理模块,并需要在特定情况下跳转到登录页。经过开发,我们使用了 vue-router 的 meta
字段进行权限控制,并使用 router.beforeEach
钩子函数进行拦截。
-- -------------------- ---- ------- ---------------------- ----- ----- -- - ----- ------------ - ---------------------- -- -------------------------- ----- ---------- - ---------------------- -- ------------- -- ------------ - --------------- - ---- - ------- - ---
这段代码的意思是:当路由需要进行权限控制,并且用户没有登录时,拦截跳转到登录页面。这段代码运行良好,我们测试通过后提交了上线。但是,在线上环境中出现了重定向问题。
问题
我们发现,在某些情况下,当跳转到登录页面后再返回原先的页面时,页面总是被重定向到登录页。使用开发者工具进行调试,发现跳转流程如下:
- 用户进入需要登录的页面,被
beforeEach
拦截,跳转到登录页; - 用户填写登录信息并登录后,跳转回原来的页面;
- 在一些特定情况下,页面会重定向到登录页。
这个问题出现的场景非常具有偶然性,我们一开始并没有很好地排查到问题所在。
排查
针对这个问题,我们进行了如下的排查:
- 调整了跳转逻辑,尝试使用
next({ path: '/login' });
的方式进行跳转,但问题依旧,说明是代码逻辑上的问题; - 在路由拦截器中加入大量 console 输出,查看跳转前后的路由信息、 meta、 用户登录状态等,发现无法得到任何有效信息;
- 调整了 Vue.js、 Vue-router 的版本,但问题没有解决。
我们认为这个问题和路由的缓存有关系,但一直无法彻底解决。直到有天,我们查看路由缓存机制文档时,发现了这么一段话:
"注意,默认情况下,Vue.js 是开启路由缓存的,因此,当你使用了 router.go(-1)
或浏览器的返回按钮返回到路由时,Vue-router 会从缓存中取得路由信息并直接显示,没有经过 beforeEach、beforeResolve
钩子函数的拦截。"
我们认为这句话就是问题的关键所在,我们使用的是 router.go(-1)
进行返回按钮操作,但是这样就跳过了拦截器的执行。因此,当页面重定向回来时,拦截函数没有被执行,导致了跳转问题。
解决
我们的解决方案非常简单,禁用路由缓存,强制让每一次返回操作都重新加载:
-- -------------------- ---- ------- ----- ------ - --- ----------- ----- ---------- ------- ------------------ ----- -------------- - ------ - -- -- -- - -- -- -- ----------- -------------------- ----- ----- - ------------------- - ------ ------- -- -------------------- ----- ----- - -- ------------------ --- ----- - ------------------- - ------ - ------- - ---
在之前,我们还没有学习到这个解决方案,但这一次排查之后,我们意识到开发过程中代码的运行环境和测试环境可能存在差异,需要在排查问题时仔细地分析环境和代码逻辑,不能仅仅靠根据开发过程中的语法和调试工具进行排查。同时,我们对 Vue.js 和 Vue-router 的缓存机制有了更深入的了解,这对我们后续的开发也非常有帮助。
结论
通过这次问题的排查和解决,我们学到了以下内容:
- Vue.js 和 Vue-router 的缓存机制;
- Vue-router 的跳转流程;
- 跳转逻辑的影响可以有很多,环境差异和用户操作丰富程度都需要考虑;
- 排查问题需要深入代码,在开发过程中需要多加留意细节问题。
参考
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/66fc66a444713626016d90e9