如何处理来自 api 响应的数据然后 return 在 angular 中同步处理布尔值?

How to process data from api response then return a boolean value synchronously in angular?

我的服务中有一个简单的功能:

  /**
   * Funtion to check if the user logged in has admin rights
   */
  isAdmin(user_id: string) {
    var adminTemp: boolean;
    this.httpClient
        .get(`${this.urk}/${user_id}`)
        .subscribe((data: any) => {
          if (data.includes('Admin')) {
            adminTemp = true;
          } else {
            adminTemp = false;
          }
        });
    return adminTemp;
  }

此函数在 canActivate 函数中调用,该函数需要一个布尔值来确定用户是否是管理员。

canActivate(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
    if(this.loginService.isAdmin('123')){
      return true;
    }
    else{
      return this.router.parseUrl("/admin/logout");
    }
  }

问题是在调用 api 之前,它采用未定义的值并将用户标记为非管理员。我知道发生这种情况是因为订阅本身是一个异步调用。我找不到任何其他方法来弄清楚如何做到这一点,因为必须先处理 api 响应才能知道他们是否是用户,否则我会使用简单的 return 语句。我该如何进行?

你的问题是你没有利用响应式编程(这是 Angular 在 Rxjs 的帮助下带来的最大优势之一)。

在你的函数 isAdmin() 中它调用异步的 http,你不确定当你 return adminTemp 时,它已经被分配了来自 http 结果的值。

相反,您不应该订阅来自 asAdmin 的 http 调用,只是 return 它是可观察的,并让 canActive 处理它。所以try not to subscribe if you can avoid it,会帮你提高效率。

      isAdmin(user_id: string): Observable<boolean> {
        
        return this.httpClient
            .get(`${this.urk}/${user_id}`)
            .pipe(
               switchMap((data) => {
                 if (data.includes('Admin')) {
                   return of(true);
                 } else {
                  return of(false);
                 }
                })
             );
        
      }

优点是canActive()也可以returnObservable,所以你可以很方便的在canActive()中使用,如下:

    canActivate(
        next: ActivatedRouteSnapshot,
        state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
        return this.loginService.isAdmin('123').pipe(
     map((res) => {
      if (res) {
         return true;
      } else {
         return  this.router.parseUrl("/admin/logout");   
      }
     })
 );

      }