我在使用 Angular Guards 从 API 获取用户信息时遇到问题。我的目标是在本地存储中始终保留最新的用户数据。我想确保每当路线发生变化时都能从 API 获取最新数据。
为了实现这一目标,我一直在使用守卫来调用 API 并获取用户信息。然而,问题在于,当在守卫内调用 API 时,会导致打开页面(路由)出现延迟,因为守卫会等待 API 响应才能继续操作。因为我创建了一个函数顺序守卫,它按顺序处理每个守卫,而不是异步处理,正如您在路线中看到的那样,我的一条路线有多个守卫,并且在继续其他路线之前我需要来自用户 API 的新数据。
我不太喜欢这种方法,因为它在页面导航中引入了不必要的等待时间。所以,我想知道是否有更好的解决方案,可以在不等待API响应的情况下更改路由,并且可以在后台异步获取用户数据,但之后它将传递来自守卫的逻辑或将其从页面踢出- 因为守卫是为了保护用户不访问基于其自身属性的页面,例如如果用户未登录,则他无法访问 /home 页面等。
sequentialGuards()
export function sequentialGuards(guards: CanActivateFn[]): CanActivateFn {
return (route, state) => {
const injectionContext = inject(Injector);
// Convert an array into an observable.
return from(guards).pipe(
// For each guard, fire canActivate and wait for it to complete.
concatMap((guard) => {
return runInInjectionContext(injectionContext, () => {
var guardResult = guard(route, state);
if (guardResult instanceof Observable) {
return guardResult;
} else if (guardResult instanceof Promise) {
return from(guardResult);
} else {
return of(guardResult);
}
});
}),
// Don't execute the next guard if the current guard's result is not true.
takeWhile((value) => value === true, true),
// Return the last guard's result.
last()
);
};
}
路线
{
path: 'home',
component: HomeComponent,
canActivate: [sequentialGuards([authGuard, verifyGuard, onboardGuard])],
},
{
path: 'documents',
component: DocumentsComponent,
canActivate: [sequentialGuards([authGuard, verifyGuard, onboardGuard])],
},
authGuard
export const authGuard: CanActivateFn = (route, state) => {
const url: string = decodeURIComponent(state.url);
return inject(CheckLoginService).checkLogin(url);
};
检查登录服务
export class CheckLoginService {
constructor(private authService: AuthService,
private tokenService: TokenService,
private userService: UserService,
private router: Router) {
}
checkLogin(url: string): Observable<boolean> {
return this.authService.user().pipe(
switchMap(() => {
if (this.tokenService.getToken() && this.userService.getUser()) {
return of(true);
}
this.authService.redirectUrl = url;
this.router.navigate(['/login'], {queryParams: {returnUrl: url}});
return of(false);
}),
catchError(() => {
this.authService.redirectUrl = url;
this.router.navigate(['/login'], {queryParams: {returnUrl: url}});
return of(false);
})
);
}
}
在根组件中,在每个
NavigationEnd
上触发 API 调用。
ngOnInit() {
this.firstChildData$ = this.router.events.pipe(
filter((e): e is NavigationEnd => e instanceof NavigationEnd),
map(e => {
// make the API call here
})
);
}