-1

我有一个 Angular 7 应用程序,其中我有一个电话后呼叫,并且基于该电话后响应,我想让警卫处于活动/非活动状态。我有这样的路线守卫

canActivate = (_router: ActivatedRouteSnapshot): boolean => {
    console.log('in link expiry guard')
    let userEmail = _router.paramMap.get('email');
    let isAllow;

    console.log('params : ', userEmail)
    userEmail = this._utilityService.decryptMsgByCryptoJs(userEmail);
    console.log('user email : ', userEmail)
    this._dataService.post(this._const.userResetPasswordLinkExpiry, { email: userEmail }).subscribe(resp => {
        console.log('verify response : ',resp)
        if (resp.success) {
            console.log('in success')
            isAllow = true;
        } else {
            isAllow = false;
        }
    })
    console.log('allow flag  : ',isAllow)
    if (isAllow) {
        console.log('in allow')
        return true;
    } else {
        console.log('in not allow')
        this._utilityService.navigate('/login');
        this._dataService.exhangeResetPasswordObsMsg({ event: 'linkExpired' });
        return false;
    }
}

但问题是,当我的http post通话正在进行时,我的警卫完全执行并返回 false,之后响应来自 post call。我该如何管理这种情况,以便根据http post呼叫响应使路由为真或假。

4

1 回答 1

0

如果要在canActivate函数中发出 Http 请求,则需要返回 anObservable<boolean>而不是 a boolean,因为您现在正在执行异步操作。

而且由于您想在失败时导航,因此您应该返回Observable<boolean | UrlTree>

简单版

constructor(private router: Router) { }

canActivate(route: ActivatedRouteSnapshot, 
    state: RouterStateSnapshot): Observable<boolean | UrlTree> {
  return this.http.post(url, body).pipe(
    map((resp: any) => resp.success ? true : this.router.parseUrl('/path'))
  );   
}

我们正在返回可观察的 http 请求(路由器将通过订阅来调用它),并将响应映射到

  • true- 路由器可以继续到受​​保护的路由
  • UrlTree- 路由器应该导航到我们返回的路由

应用于您的示例

如果我们将此应用于您的示例,我们需要在管道中做更多的工作,因为您有一个额外的服务调用。

// TODO: inject other services
constructor(private router: Router) { }

canActivate(route: ActivatedRouteSnapshot, 
      state: RouterStateSnapshot): Observable<boolean | UrlTree> {
    const userEmail = route.paramMap.get('email');

    // I am assuming this is a synchronous call
    userEmail = this._utilityService.decryptMsgByCryptoJs(userEmail);

    const url = this._const.userResetPasswordLinkExpiry;
    const body = { email: userEmail };

    return this._dataService.post(url, body).pipe(
      // initial map from response to true/false
      map((resp: any) => resp.success),

      // perform an action if false
      tap(success => {
        if (!success) {
          // I'm assuming this is synchronous. If not, you will need to do a switchMap
          this._dataService.exhangeResetPasswordObsMsg({ event: 'linkExpired' });
        }
      }),
      // final map to boolean | UrlTree
      map(success => success ? true : this.router.parseUrl('/login'))
    );   
}

我假设那里有一些服务调用是同步的。这个答案演示了如何在内部执行异步调用canActivate并允许路由器导航或返回要导航到的替代路由。

于 2020-02-25T20:32:06.860 回答