AngularJS基于Promise控制路由显隐时刷新出现404错误求助
问题成因
你遇到的404问题本质是AngularJS路由的注册时机问题:$stateProvider的路由注册属于框架启动的配置阶段同步行为,你把路由注册逻辑包裹在异步fetch的结果判断里,刷新页面时AngularJS路由初始化会先执行,此时异步请求还没返回结果,maintenance.correspondence路由还没注册,路由系统匹配不到对应路径就会直接抛出404。而你从其他页面导航过来时异步请求已经返回、路由已经完成注册,所以表现正常。
解决方案
不要用异步结果控制路由是否注册,改为正常注册路由,把权限校验逻辑放到路由的resolve配置中实现:
resolve会在路由进入前执行你传入的逻辑,返回promise,只有promise被resolve时才会正常进入路由,否则会中断路由跳转。
代码实现
// 始终注册路由,不要加外层toggle条件判断 $stateProvider.state('maintenance.correspondence', { url: '/correspondence', data: { title: 'Correspondence', header: { heading: 'Correspondence', subheading: 'Correspondence' } }, template: '<correspondence></correspondence>', controller: ($scope: IScope) => { }, onExit: (BreadCrumbs: BreadCrumbs) => { BreadCrumbs.reset(); }, onEnter: (BreadCrumbs: BreadCrumbs, $stateParams: IStateParamsService) => { BreadCrumbs.add("Correspondence", "Correspondence", null, "maintenance.correspondence"); }, // 新增resolve块做开关校验 resolve: { pageAccess: ($q, $state) => { return fetch("/pageToggle") .then(response => response.json()) .then(response => { const toggle = parseInt(response) === 1; if (toggle) { // 开关打开,正常放行 return true; } // 开关关闭,跳转404页,替换为你项目实际的404路由名 $state.go('404'); return $q.reject('无页面访问权限'); }) .catch(() => { $state.go('404'); return $q.reject('开关接口请求失败'); }); } } });
优化建议
AngularJS项目优先使用内置的$http服务发起请求,不需要手动封装$q,也不会出现数据变更后视图不同步的问题,改造后resolve逻辑如下:
resolve: { pageAccess: ($http, $q, $state) => { return $http.get('/pageToggle') .then(response => { const toggle = parseInt(response.data) === 1; if (!toggle) { $state.go('404'); return $q.reject('无页面访问权限'); } return true; }) .catch(() => { $state.go('404'); return $q.reject('开关接口请求失败'); }); } }
导航入口隐藏处理
如果你需要在侧边栏、导航栏隐藏该路由的入口,可以把接口返回的开关状态存在全局权限服务或者$rootScope中,在导航对应的DOM节点上加ng-if="toggle"判断即可,不需要控制路由注册逻辑。
内容的提问来源于stack exchange,提问作者Raja R
相关产品推荐
相关产品推荐

