订阅路由守卫中的可观察对象及其含义
Subscribing to observables in route guards and its implications
我有一个名为 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']);
}
})
);
}
}
并根据此数据执行必要的 canActivate
或 canActivateChild
检查。通过在子路由中添加 console.log()
并从 permissions$
发出新数据,我可以看到 observable 仍然处于活动状态,即使守卫已经 "used" 并且路由已激活。当我去 path: ':company'
以外的路线时,我期待它会消失,但是守卫并没有被摧毁。
这引出了我的问题:
我这样做正确吗?我希望使用守卫来检查用户是否有任何权限,但同时我只想执行一次 HTTP 权限请求(当导航到 path: ':company'
或其任何子项时)。我担心如果我像这样使用守卫,由于大量的观察者,它会及时减慢整个应用程序。
emitting new data from permissions$ inside the children routes I can see that the observable is still active, even though the guard has been "used" and the route is activated.
首先,permissions$
仍然有效,因为您从未取消订阅您的守卫。 angular 将守卫创建为单例。
即使守卫不是单例,守卫的实例仍然通过 this.permissions
在订阅中引用,并且如果您的 observable 作为变量存在于您的 auth 服务中(我假设它是一个单例)这个绑定还会阻止垃圾回收。
This brings me to my question: Am I doing this correctly? I wish to use a guard to check if the user has any permissions,
在你的守卫中发出请求是完全可以的,例如获取权限。
but at the same time I want to perform the HTTP request for permissions only once (when navigating to path: ':company' or any of its children).
如果您只想发出一次请求,那么您应该考虑在您的身份验证服务中使用 shareReplay,以便所有未来连接的实例都使用相同的先前发出的值。
我有一个名为 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']);
}
})
);
}
}
并根据此数据执行必要的 canActivate
或 canActivateChild
检查。通过在子路由中添加 console.log()
并从 permissions$
发出新数据,我可以看到 observable 仍然处于活动状态,即使守卫已经 "used" 并且路由已激活。当我去 path: ':company'
以外的路线时,我期待它会消失,但是守卫并没有被摧毁。
这引出了我的问题:
我这样做正确吗?我希望使用守卫来检查用户是否有任何权限,但同时我只想执行一次 HTTP 权限请求(当导航到 path: ':company'
或其任何子项时)。我担心如果我像这样使用守卫,由于大量的观察者,它会及时减慢整个应用程序。
emitting new data from permissions$ inside the children routes I can see that the observable is still active, even though the guard has been "used" and the route is activated.
首先,permissions$
仍然有效,因为您从未取消订阅您的守卫。 angular 将守卫创建为单例。
即使守卫不是单例,守卫的实例仍然通过 this.permissions
在订阅中引用,并且如果您的 observable 作为变量存在于您的 auth 服务中(我假设它是一个单例)这个绑定还会阻止垃圾回收。
This brings me to my question: Am I doing this correctly? I wish to use a guard to check if the user has any permissions,
在你的守卫中发出请求是完全可以的,例如获取权限。
but at the same time I want to perform the HTTP request for permissions only once (when navigating to path: ':company' or any of its children).
如果您只想发出一次请求,那么您应该考虑在您的身份验证服务中使用 shareReplay,以便所有未来连接的实例都使用相同的先前发出的值。