You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 08:59:20