【问题标题】:Angular - How to make canActivate to await for promise response?Angular - 如何使 canActivate 等待承诺响应?
【发布时间】:2020-04-28 19:29:03
【问题描述】:

如果用户已登录,我会尝试签入 CanActivate gurad。
如果是,那么我将他导航到某个页面。
如果没有,那么我将他导航到登录页面。
我使用承诺。

我有一个名为 LoginService 的服务:

export class LoginService {

  urlcheck = 'http://localhost:80/isconnected.php';
  resultCheck;

  constructor(private http: HttpClient, private router: Router)
  {
  }

  async checkLogin()
  {
    const x = await this.updateConnectedState();
    return x;
  }

  updateConnectedState()
  {
    //formData here...
    return this.http.post(this.urlcheck, formData).toPromise()
      .then(
        (response) =>
        {
          this.resultCheck = response; 
          console.log(response);
          return this.resultCheck.state; //state is true/false
        },
        (error) => 
        { 
            console.log(error); 
            return false;  
        }
      );
    }
  }


canActivate Gurad:

export class BackHomeGuardService implements CanActivate
{
  constructor(private logService: LoginService, private router: Router)
  {
  }

  canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean>|boolean
  {
    const result = this.logService.checkLogin();
    console.log( result);

    if (result)
    {
      console.log('true');
      // navigate to hom page
      return true;
    }
    else
    {
      console.log('false');
      // navigate to login page
      return false;
    }
  }
}

守卫 canActivate 函数总是返回 true。
我检查了控制台,承诺结果是:

__zone_symbol__state: null
__zone_symbol__value: []

我想让 canActive 在它做某事之前等待结果。
如果我的后端(php 代码文件)需要 30 秒才能完成怎么办?
我需要一个解决方案。谢谢。

【问题讨论】:

    标签: angular promise


    【解决方案1】:

    根据CanActivate的类型:

    export declare interface CanActivate {
        canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree;
    }
    

    canActivate 方法可以返回 Observable、Promise 或布尔值。

    您可以像这样简单地返回您的checkLogin() 电话:

    canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean>|boolean {
        return this.logService.checkLogin();
    }
    

    一切都会好起来的。


    更新

    回答问题“如何处理我的 canActivate 中返回的布尔值”来自 cmets

    CanActivate 的想法是由于某种条件限制对某些路由的访问。您可以通过链接您的 Promise 或 Observable 来执行一些副作用(但我不确定它们将如何显示,除非它是 console.log):

    canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean>|boolean {
        return this.logService
          .checkLogin()
          .then(canLogin => {
             console.log('Can user login:', canLogin);
             // perform you side effects here
          })
    
    }
    

    【讨论】:

    • 它不起作用...我也想处理结果
    • 它只有在我使用时才有效:return this.logService.checkLogin();我想处理 canActivate 中的布尔值。该怎么做?
    • canActivate 的思想是根据某些条件显示或隐藏某些路由。 handle the boolean是什么意思(你要执行什么操作)?
    • 也不行
    【解决方案2】:

    如果看canActivate方法的返回类型:

    canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree
    

    }

    它可以返回一个简单的布尔值、Promise 或 Observable。另外,我认为您不需要在 LoginService 中将 Observable 转换为 Promise。

    【讨论】:

    • 我将其更改为 observable 并在 canActivate 中使用 return this.logService.checkLogin();但我不知道如何处理布尔结果...
    【解决方案3】:

    canActivate 可以与 observable 一起使用,因此您可以将查询结果映射为以这种方式返回 observable

    import { of, Observable } from 'rxjs';
    import { catchError, map } from 'rxjs/operators';
    
    export class LoginService {
    
      urlcheck = 'http://localhost:80/isconnected.php';
      resultCheck;
    
      constructor(private http: HttpClient, private router: Router) {
      }
    
      checkLogin(): Observable<boolean> {
    
        //formData here...
        return this.http.post(this.urlcheck, formData).pipe(
          map(
            (response) => {
              this.resultCheck = response;
              console.log(response);
              return this.resultCheck.state; //state is true/false
            }),
            catchError(error => {
              console.log(error);
              return of(false);
            })
          );
      }
    }
    
    export class BackHomeGuardService implements CanActivate
    {
      constructor(private logService: LoginService, private router: Router)
      {
      }
    
      canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean>
      {
        return this.logService.checkLogin();
      }
    }
    

    【讨论】:

      【解决方案4】:

      canActivate 可以具有以下返回类型:booleanPromise&lt;boolean&gt;Observable&lt;boolean&gt;

      因为你已经有checkLogin() 来返回一个Promise,它会解析为true/false。让我们坚持使用PromiseObservable。正如其他人已经回答的那样,您绝对可以直接返回this.logService.checkLogin()

         canActivate(): Promise<boolean> {
            return this.logService.checkLogin();
         }
      

      现在,我发现您还想根据 checkLogin() 值导航到其他地方。我建议将Promise 转换为Observable,以便您可以利用tap 运算符。你可以这样做:

         return fromPromise(this.logService.checkLogin()).pipe(
            tap(isLogin => {
               if (!isLogin) {
                  // not login. navigate to login page
               }
            })
         )
      

      我们真的不想导航到 true 上的某个地方,因为当它是真的时,Guard 会将用户导航到被保护的路线。

      【讨论】:

      • 如果我想使用 observable 而不是 promise?谢谢
      • fromPromise 是要走的路
      • 或者你的意思是你想使用Promise而不是Observable
      猜你喜欢
      • 2018-01-17
      • 1970-01-01
      • 2022-11-16
      • 2017-04-04
      • 1970-01-01
      • 2018-05-29
      • 1970-01-01
      • 2013-09-16
      • 2022-01-26
      相关资源
      最近更新 更多