Angular9中如何在canActivate调用前加载服务端API数据
问题根源
你当前的异常是因为异步逻辑处理顺序错误导致的:
- 健康检查接口是异步请求,你在
checkForApplicattionHeath方法里内部订阅后直接同步返回未赋值的res,初始状态下必然是undefined - CanActivate方法中直接同步返回还没收到异步回调的
message变量,路由守卫拿到undefined会直接判定校验失败 - 错误回调里
return false写在路由跳转前面,跳转逻辑永远不会执行
修复方案
第一步:修改DataService代码
- 健康检查方法不要内部订阅,直接返回Observable流,交给路由守卫处理
- 修正错误处理的执行顺序,先跳转再返回false
- 可选添加状态缓存,避免每次路由触发都重复调用健康检查接口
import { Injectable } from '@angular/core'; import {BehaviorSubject, Observable, of} from 'rxjs'; import {ApiService} from "./services/api.service"; import {Router} from "@angular/router"; import {catchError, map} from 'rxjs/operators'; @Injectable({ providedIn: 'root' }) export class DataServiceService { // 缓存健康状态,避免重复请求 private healthStatus: boolean | null = null; constructor(private apiService: ApiService, private router: Router) { } checkForApplicattionHeath(): Observable<boolean> { // 如果已经有缓存状态直接返回 if (this.healthStatus !== null) { return of(this.healthStatus); } const url = 'test'; return this.apiService.getMethod(url).pipe( map((response: Response) => { console.log('健康检查通过'); this.healthStatus = true; // 你可以在这里加数据库状态校验逻辑 return true; }), catchError((error) => { console.error('健康检查失败', error); this.healthStatus = false; this.router.navigate(['maintenance']); return of(false); }) ); } }
第二步:修改ApplicationStatusGuard代码
- 不需要在构造函数里提前调用健康检查,在canActivate触发时调用即可
- 直接返回Observable流,Angular路由守卫会自动等待流返回结果后再执行路由判定
import { Injectable } from '@angular/core'; import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router'; import {Observable} from 'rxjs'; import {DataServiceService} from "./data-service.service"; @Injectable({ providedIn: 'root' }) export class ApplicationStatusGuard implements CanActivate{ constructor(private data: DataServiceService) {} canActivate( next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> { return this.data.checkForApplicattionHeath(); } }
第三步:修正路由配置
注意maintenance路由不要添加这个守卫,避免进入死循环:
const routes: Routes = [ { path: 'maintenance', component: MaintenanceScreenComponent }, { path: 'license', component: LicenseComponent, canActivate:[ApplicationStatusGuard]}, // 其他需要校验的路由都加这个守卫 ];
补充说明
如果需要应用初始化阶段就完成健康检查,不用等到第一次路由触发才校验,可以在AppModule的providers里添加APP_INITIALIZER提前执行健康检查逻辑,这样应用加载前就会完成状态校验。
内容的提问来源于stack exchange,提问作者Sam
相关产品推荐
相关产品推荐

