为什么 canLoad 函数在重新路由期间会导致无限循环?
Why is canLoad function resulting in infinite loop during reroute?
我在我的 AuthGuard 中使用 Angular 的 canLoad 函数来验证我应用根目录下的延迟加载模块。
如果用户未通过身份验证,则不会加载模块并将用户导航至登录页面。这与 canActivate 一起工作得很好,但在我的 canLoad 应用程序启动期间导致无限循环。
我不确定循环是在哪里或如何产生的,因为我的 auth 组件是另一个模块的一部分,然后是我要加载的模块,并且重定向不是到根目录。我发现了类似的 problems/articles 但他们的案例更加明显。
AppRoutingModule
const routes: Routes = [
{
path: '',
component: AdminLayoutComponent,
canLoad: [AuthGuard],
loadChildren: () => import('./_layouts/admin-layout/admin-layout.module').then(mod => mod.AdminLayoutModule)
},
{
path: 'login',
component: AuthComponent
},
{
path: '404',
component: PageNotFoundComponent,
}
];
AuthGaurdService
@Injectable({
providedIn: 'root',
})
export class AuthGuard implements CanActivate, CanLoad {
constructor(private router: Router, private userService: UserService) {}
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
return this.userService.isAuthenticated.pipe(take(1)).map(auth => {
if (auth == true) {
return true;
}
console.warn('User not authenticated. ACCESS DENIED.');
// navigate to login page
this.router.navigate(['/login']);
// you can save redirect url so after authing we can move them back to the page they requested
return false;
});
}
canLoad(route: Route, segments: UrlSegment[]): Observable<boolean> | Promise<boolean> | boolean {
return this.userService.isAuthenticated.pipe(take(1)).map(auth => {
if (auth == true) {
return true;
}
console.warn('User not authenticated. ACCESS DENIED.');
// navigate to login page
this.router.navigate([route.path + '/login']);
// you can save redirect url so after authing we can move them back to the page they requested
return false;
});
}
}
AuthComponent 提交方法
submitForm(): void {
this.isSubmitting = true;
this.errors = {errors: {}};
const credentials = (this.authType == 'login' ? this.loginForm.value : this.registerForm.value);
this.userService
.attemptAuth(this.authType, credentials).subscribe(
data => {
console.log('Redirecting to profile');
// Make profile default
this.router.navigateByUrl('/profile');
},
err => {
console.log('ERROR: ', err);
this.errors = err;
this.isSubmitting = false;
// Redirect back to register/login
}
);
配置中路由的顺序很重要,这是设计使然。路由器在匹配路由时采用先匹配优胜策略,因此更具体的路由应该放在不太具体的路由之上。在上面的配置中,首先列出具有静态路径的路由,然后是与默认路由匹配的空路径路由。通配符路由排在最后,因为它匹配每个 URL,只有在没有其他路由首先匹配时才应选择。
(引自 https://angular.io/guide/router)
我在我的 AuthGuard 中使用 Angular 的 canLoad 函数来验证我应用根目录下的延迟加载模块。
如果用户未通过身份验证,则不会加载模块并将用户导航至登录页面。这与 canActivate 一起工作得很好,但在我的 canLoad 应用程序启动期间导致无限循环。
我不确定循环是在哪里或如何产生的,因为我的 auth 组件是另一个模块的一部分,然后是我要加载的模块,并且重定向不是到根目录。我发现了类似的 problems/articles 但他们的案例更加明显。
AppRoutingModule
const routes: Routes = [
{
path: '',
component: AdminLayoutComponent,
canLoad: [AuthGuard],
loadChildren: () => import('./_layouts/admin-layout/admin-layout.module').then(mod => mod.AdminLayoutModule)
},
{
path: 'login',
component: AuthComponent
},
{
path: '404',
component: PageNotFoundComponent,
}
];
AuthGaurdService
@Injectable({
providedIn: 'root',
})
export class AuthGuard implements CanActivate, CanLoad {
constructor(private router: Router, private userService: UserService) {}
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
return this.userService.isAuthenticated.pipe(take(1)).map(auth => {
if (auth == true) {
return true;
}
console.warn('User not authenticated. ACCESS DENIED.');
// navigate to login page
this.router.navigate(['/login']);
// you can save redirect url so after authing we can move them back to the page they requested
return false;
});
}
canLoad(route: Route, segments: UrlSegment[]): Observable<boolean> | Promise<boolean> | boolean {
return this.userService.isAuthenticated.pipe(take(1)).map(auth => {
if (auth == true) {
return true;
}
console.warn('User not authenticated. ACCESS DENIED.');
// navigate to login page
this.router.navigate([route.path + '/login']);
// you can save redirect url so after authing we can move them back to the page they requested
return false;
});
}
}
AuthComponent 提交方法
submitForm(): void {
this.isSubmitting = true;
this.errors = {errors: {}};
const credentials = (this.authType == 'login' ? this.loginForm.value : this.registerForm.value);
this.userService
.attemptAuth(this.authType, credentials).subscribe(
data => {
console.log('Redirecting to profile');
// Make profile default
this.router.navigateByUrl('/profile');
},
err => {
console.log('ERROR: ', err);
this.errors = err;
this.isSubmitting = false;
// Redirect back to register/login
}
);
配置中路由的顺序很重要,这是设计使然。路由器在匹配路由时采用先匹配优胜策略,因此更具体的路由应该放在不太具体的路由之上。在上面的配置中,首先列出具有静态路径的路由,然后是与默认路由匹配的空路径路由。通配符路由排在最后,因为它匹配每个 URL,只有在没有其他路由首先匹配时才应选择。 (引自 https://angular.io/guide/router)