【问题标题】:Subscribing to observables in route guards and its implications订阅路由守卫中的 observables 及其含义
【发布时间】:2019-03-26 22:23:02
【问题描述】:

我有一个名为 PermissionGuard 的路由器保护程序,它在此处启动

const routes: Routes = [
  {
    path: ':company',
    component: CompanyComponent,
    canActivate: [PermissionGuard],
    canActivateChild: [PermissionGuard],
    children: [
      {
        path: '',
        component: IndexComponent
      },
      {
        path: 'projects',
        loadChildren: '../projects/projects.module#ProjectsModule'
      },
    ]
  }
];

在我的PermissionGuard 中,我订阅了PermissionService,如下所示:

export class PermissionGuard implements CanActivate, CanActivateChild {

  private permissions: Permission[];

  constructor(private permissionService: PermissionService, private router: Router) {
    this.permissionService.permissions$.subscribe(
      (permissions: Permission[]) => {
        this.permissions = permissions;
      }
    );
  }

  canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> {
    this.permissionService.getPermissions(next.paramMap.get('company'));
    return this.permissionService.permissionsFetchDone$
    .pipe(filter(x => x))
    .pipe(
      map(response => {
        if (this.permissions) {
          return true;
        } else {
          this.router.navigate(['/forbidden']);
        }
      })
    );
  }
}

并根据此数据执行必要的canActivatecanActivateChild 检查。通过在子路由中添加console.log() 并从permissions$ 发出新数据,我可以看到observable 仍然处于活动状态,即使已经“使用”了警卫并且激活了路由。当我去path: ':company'以外的路线时,我期待它会消失,但是守卫没有被摧毁。

这让我想到了我的问题: 我这样做正确吗?我希望使用警卫来检查用户是否有任何权限,但同时我只想执行一次 HTTP 权限请求(导航到 path: ':company' 或其任何子级时)。恐怕如果我使用这样的守卫,由于大量的观察者,它会及时减慢整个应用程序的速度。

【问题讨论】:

    标签: angular rxjs6 angular-observable angular-guards


    【解决方案1】:

    在子路由中从权限 $ 发出新数据我可以看到 observable 仍然处于活动状态,即使防护已被“使用”并且路由已激活。

    首先,permissions$ 仍然处于活动状态,因为您从未取消订阅。并且 Angular 将守卫创建为单例。

    即使守卫不是单例,守卫的实例仍然通过this.permissions 在订阅中引用,并且如果您的可观察对象作为变量存在于您的身份验证服务中(我假设是单例),此绑定也会阻止垃圾回收。

    这让我想到了我的问题:我这样做是否正确?我希望使用警卫来检查用户是否有任何权限,

    在你的警卫中发出请求完全没问题,例如获取权限。

    但同时我只想执行一次 HTTP 权限请求(导航到路径:':company' 或其任何子级时)。

    如果您只想发出一次请求,那么您应该考虑在您的身份验证服务中使用shareReplay,以便所有未来连接的实例都使用之前发出的相同值。

    【讨论】:

    • 我只希望每个:company id 及其在子路线中的导航发布一次,也就是。当公司发生变化时,需要一个新的http请求。然而,我最关心的是会出现的 observables 的数量,但是,由于守卫是单身人士,老实说,我没有看到任何其他选择。或者角度守卫是否有我可以取消订阅的 ngAfterActivation 版本?
    • 当您在注册了警卫的路线(例如:company)中导航时,每次都会调用警卫的can,因此您可以订阅can方法而不存储您的结果在this.permissions 中,然后取消订阅(如果您的 observable 在您的身份验证服务中作为变量保存,您只需要取消订阅)。
    • “或者 Angular 守卫有我可以取消订阅的 ngAfterActivation 版本吗?”并不真地;您可以使用CanDeactivate 接口,但这实际上是用于决定是否可以停用路由,而不是用于取消订阅。
    猜你喜欢
    • 1970-01-01
    • 2018-12-04
    • 2018-12-20
    • 2018-11-14
    • 2019-02-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多