Angular Router Guard 在最终结果为真时未解析

Angular Router Guard not resolving when the end result is true

当最后的 if 语句为真时,以下代码可以正常工作。当最终 if 语句为 false 时,永远不会解析请求的路由。我试过添加等待和异步。我已经尝试将代码移动到一个单独的函数中,该函数 returns 一个带有布尔值的 await 并且没有任何东西可以在应该的时候解析路由。当它应该拒绝重定向到设置时它总是有效。

If语句

if(moduleSnapshot.size >= planLimit) {
   this.toast.info(`You've reached your plan maximum, upgrade to add more ${mod}.`, 'Plan Maximum');
   this.router.navigateByUrl('/settings/profile/subscription');
   return false;
}
return true;

完整路由器防护

import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot, UrlTree } from '@angular/router';
import { Observable } from 'rxjs';

import { ToastrService } from 'ngx-toastr';
import { AngularFirestore } from '@angular/fire/firestore';
import { AuthService } from '../services/auth/auth.service';
import { SubscriptionsService } from '../services/subscriptions/subscriptions.service';

@Injectable({
  providedIn: 'root'
})
export class SubscriptionGuard implements CanActivate {

  constructor( private router: Router, private toast: ToastrService, private authService: AuthService, private subscriptionService: SubscriptionsService, private afs: AngularFirestore ) { }

  canActivate( route: ActivatedRouteSnapshot, state: RouterStateSnapshot ): any {
    this.authService.userData.subscribe((observer1) => {
      if(observer1) {
        let subscriptions = this.subscriptionService.fetchUserSubscription(observer1.uid);
        subscriptions.onSnapshot((observer:any) => {
          observer.forEach((subscription:any) => {
            if(subscription.exists) {
              this.authService.allUserData.subscribe( async(userDataObserver:any) => {
                let mod:string = state.url.split('/')[1];
                await this.subscriptionService.fetchPlan(subscription.data().productID).then((plan:any) => {
                  let planLimit:number = parseInt(plan.metadata[mod]);
                  let companyUid:string = userDataObserver.companies[0].company;
                  this.afs.collection('companies').doc(companyUid).collection(mod).ref.get().then((moduleSnapshot:any) => {
                    if(moduleSnapshot.size >= planLimit) {
                      this.toast.info(`You've reached your plan maximum, upgrade to add more ${mod}.`, 'Plan Maximum');
                      this.router.navigateByUrl('/settings/profile/subscription');
                      return false;
                    }
                    console.log('Plan max not met, should resolve');
                    return true;
                  });
                });
              });
            }
          });
        });
      }
    });
  }
  
}

根据 Angular 的实现,canActivate 方法(CanActivate 接口需要)需要 return 类型。

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

无需深入研究路由守卫的逻辑,我能看到的是您实际上没有 returning 任何东西。因为 userData 是一个 Observable,所以订阅逻辑是异步处理的。这意味着 canActivate 方法由路由器调用,订阅逻辑异步启动,然后方法调用解析为无值。

要解决此问题,您需要 return 包含布尔值的 Observable 流。为此,我建议将 rxjs .pipe().switchMap() 运算符结合使用,以保留订阅逻辑。

return this.authService.userData.pipe(
    switchMap((user) => {
        // Handle subscription logic and return observable of a boolean value
        return this.someService.doSomething();
    })
);