Angular路由守卫失效问题:基于API返回值控制路由访问
Angular路由权限控制问题排查与修复
需求
根据API返回值控制用户对特定URL(/request/create)的访问权限
现有代码
路由配置
{ path: 'request', component: RequestLayoutComponent, children: [ { path: 'create', component: JobCreateComponent, resolve: { canContinue: STResolver }, canActivateChild: [LimitGuard], runGuardsAndResolvers: 'always' }] }
STResolver代码
@Injectable({ providedIn: 'root' }) export class STResolver implements Resolve<any>{ constructor(private router: Router, private data: DataService, private inspectionService: InspectionService, private searchForm: SearchForm) {} resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> { this.searchForm.userId = this.data.localStorageFind() let search = this.searchForm search.sort = ESort.DESC this.inspectionService.getLimit(search).pipe( map((res: any) => { if (res.status == false) { return false; } return true; }) ); return } }
LimitGuard代码
@Injectable({ providedIn: 'root' }) export class LimitGuard implements CanActivate { canContinue: any constructor(private router: Router, private route: ActivatedRoute) { this.canContinue = this.route.snapshot.data.canContinue; } canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean { this.canContinue = this.route.snapshot.data.canContinue; if (this.canContinue == true) { return true; } else { this.router.navigate(['/inspections/request']); return false; } } }
问题现象
访问/request/create时抛出错误:
ERROR Error: Uncaught (in promise): Error: invalid Error: invalid at Module.lp (main.js:1:471005) at hn.children.resolve.canContinue.n.ɵfac [as factory] (798.js:1:107375) at Ph.hydrate (main.js:1:457363) at Ph.get (main.js:1:455928) at Ph.get (main.js:1:455976) at ci (main.js:1:631393) at mo (main.js:1:658002) at main.js:1:658073 at ne (main.js:1:214335) at O (main.js:1:214272) at Pe (polyfills.js:1:140142) at Pe (polyfills.js:1:139642) at polyfills.js:1:141019 at k.invokeTask (polyfills.js:1:130653) at Object.onInvokeTask (main.js:1:557682) at k.invokeTask (polyfills.js:1:130574) at k.runTask (polyfills.js:1:125676) at pe (polyfills.js:1:1330
此前尝试在Guard中直接调用API,仍出现相同错误。
问题原因与修复方案
1. Resolver的核心错误
STResolver的resolve方法根本没返回Observable!代码里创建了API请求的Observable但只是定义了,最后直接return相当于返回undefined,这直接触发了Angular路由解析的"invalid"错误。
修复后的STResolver:
@Injectable({ providedIn: 'root' }) export class STResolver implements Resolve<boolean>{ constructor(private router: Router, private data: DataService, private inspectionService: InspectionService, private searchForm: SearchForm) {} resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> { this.searchForm.userId = this.data.localStorageFind() const search = { ...this.searchForm }; // 复制对象,避免修改原实例产生副作用 search.sort = ESort.DESC; // 直接返回API请求的Observable return this.inspectionService.getLimit(search).pipe( map((res: any) => { return res.status !== false; }), catchError(() => { // 处理API请求失败的情况,比如跳转回指定页面 this.router.navigate(['/inspections/request']); return of(false); }) ); } }
2. Guard的问题
- 不能在Guard构造函数中获取
route.snapshot.data,此时路由还没完成解析,Resolver的数据还没填充 - 应该直接从
canActivate方法的入参route里取解析后的数据
修复后的LimitGuard:
@Injectable({ providedIn: 'root' }) export class LimitGuard implements CanActivate { constructor(private router: Router) {} canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean { const canContinue = route.data['canContinue']; if (canContinue) { return true; } else { this.router.navigate(['/inspections/request']); return false; } } }
3. 简化逻辑建议
其实可以把权限判断和跳转逻辑直接放在Resolver里,去掉Guard,减少冗余:
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> { this.searchForm.userId = this.data.localStorageFind() const search = { ...this.searchForm }; search.sort = ESort.DESC; return this.inspectionService.getLimit(search).pipe( map((res: any) => { if (!res.status) { this.router.navigate(['/inspections/request']); return false; } return true; }), catchError(() => { this.router.navigate(['/inspections/request']); return of(false); }) ); }
此时路由配置只保留resolve即可,无需canActivateChild。
内容的提问来源于stack exchange,提问作者Samuel
相关产品推荐
相关产品推荐

