微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

CanActivate 在 NavigationEnd

如何解决CanActivate 在 NavigationEnd

我正在尝试在 Angular 中构建一个 SubscriptionGuard。 此 Guard 应检查用户是否已支付订阅费用。

我遇到了一个奇怪的问题。我将展示代码并在之后解释这一点。


subscription.guard.ts

import { Injectable } from '@angular/core';
import { CanActivate,Router,RouterStateSnapshot,UrlTree } from '@angular/router';
import { UseRSService } from '../services/users.service';


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

    constructor(
        private useRSService: UseRSService,private router: Router
    ) { }

    async canActivate(route: any,state: RouterStateSnapshot): Promise<UrlTree> {
        const status = await this.useRSService.userSubscriptionStatus();
        let tree = this.router.parseUrl(state.url);

        // User should update payment methods.
        if (
            status === 'past_due' ||
            status === 'unpaid' ||
            status === 'incomplete'
        ) {
            tree = this.router.parseUrl('/subscription');
            tree.queryParams.subscriptionReturnUrl = state.url;
        }

        // User should create a new subscription.
        if (
            status === 'canceled' ||
            status === 'incomplete_expired' ||
            status === null
        ) {
            tree = this.router.parseUrl('/subscription');
            tree.queryParams.subReturnUrl = state.url;
            tree.queryParams.firstSub = status === null;
        }

        return tree;
    }
}

users.service.ts

// [ ... ]

async userSubscriptionStatus(): Promise<USS_Status | null> {
  const uid = (await this.getCurrentFire())?.uid;
  if (!uid) return null;
  return new Promise((resolve,reject) => {
    this.db.colWithIds$<UserStripeSubscription>(
      `users/${uid}/subscriptions`,(ref: any) => ref.orderBy('created','desc')
    )
      .pipe(take(1))
      .subscribe((subs: UserStripeSubscription[]) => {
        let timestamp: number | null = null;
        let status: string | null = null;
        subs.forEach(sub => {
          if (!sub.status) return;
          if (!timestamp) {
            timestamp = sub.created.seconds;
            status = sub.status;
            return;
          }
          if (timestamp <= sub.created.seconds) {
            timestamp = sub.created.seconds;
            status = sub.status;
            return;
          }
          return;
        });
        console.log('status =>',status);
        resolve(status);
      });
  });
}

// [ ... ]

如您所见,守卫依赖于 userSubscriptionStatus() 中的方法 users.service.ts

在第一个测试阶段,我认为 .pipe(take(1)) 因某种奇怪的原因不起作用,但经过仔细调试,我注意到问题实际上是 SubscriptionGuard 持续调用 UseRSService 中的方法

我尝试了所有方法,但不知道如何解决此问题。 这是我在控制台中得到的:

https://i.stack.imgur.com/l3p2I.png

有人可以帮忙吗?我真的不知道...

[更新 #1] 我更新了代码。现在看起来像这样:

subscription.guard.ts

import { USS_Status } from './../models/user-stripe-subscription.model';
import { Injectable } from '@angular/core';
import { CanActivate,UrlTree } from '@angular/router';
import { UseRSService } from '../services/users.service';


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

    private status: USS_Status | null | undefined = undefined;

    constructor(
        private useRSService: UseRSService,private router: Router
    ) { }

    canActivate(route: any,state: RouterStateSnapshot): Promise<UrlTree> {
        return new Promise<UrlTree>((resolve,reject) => {
            const method = () => {
                let tree = this.router.parseUrl(state.url);

                if (
                    this.status === 'past_due' ||
                    this.status === 'unpaid' ||
                    this.status === 'incomplete'
                ) {
                    tree = this.router.parseUrl('/subscription');
                    tree.queryParams.subscriptionReturnUrl = state.url;
                }

                else if (
                    this.status === 'canceled' ||
                    this.status === 'incomplete_expired' ||
                    this.status === null
                ) {
                    tree = this.router.parseUrl('/subscription');
                    tree.queryParams.subReturnUrl = state.url;
                    tree.queryParams.firstSub = this.status === null;
                    console.log('...........................................');
                    console.log('this.status === null',this.status === null,this.status);
                    console.log('this.status === canceled',this.status === 'canceled',this.status);
                    console.log('this.status === incomplete_expired',this.status === 'incomplete_expired',this.status);
                }

                resolve(tree);
            };

            if (this.status === undefined)
                this.useRSService.userSubscriptionStatus().then((status) => {
                    this.status = status;
                    method();
                    console.log('Guard status is =>',status);
                });
            else method();
        });
    }
}

users.service.ts

// [...]

async userSubscriptionStatus(): Promise<USS_Status | null> {
  const uid = (await this.getCurrentFire())?.uid;
  if (!uid) return null;
  return new Promise((resolve,'desc')
    )
      .pipe(take(1))
      .subscribe((subs: UserStripeSubscription[]) => {
        let timestamp: number | null = null;
        let status: string | null = null;
        console.log('SUBS are => ',subs);
        subs.forEach(sub => {
          if (!sub.status) return;
          if (!timestamp) {
            timestamp = sub.created.seconds;
            status = sub.status;
            return;
          }
          if (timestamp <= sub.created.seconds) {
            timestamp = sub.created.seconds;
            status = sub.status;
            return;
          }
          return;
        });
        console.log('status =>',status);
        resolve(status);
      });
  });
}

// [...]

我的控制台现在看起来像这样...

........................................... // subscription.guard.ts
'this.status === null' true null // subscription.guard.ts
'this.status === canceled' false null // subscription.guard.ts
'this.status === incomplete_expired' false null // subscription.guard.ts
'Guard status is =>' null // subscription.guard.ts

[WDS] Live Reloading enabled. // ANGULAR

'SUBS are =>' (2) [{…},{…}] // users.service.ts
'status =>' 'active' // users.service.ts

........................................... // subscription.guard.ts
'this.status === null' true null // subscription.guard.ts
'this.status === canceled' false null // subscription.guard.ts
'this.status === incomplete_expired' false null // subscription.guard.ts

服务似乎只在守卫之后运行。我真的不知道该怎么做...

解决方法

从控制台日志输出可以看出您的 userService 首先运行

使用接受参数 methodstatusParam 函数更新您的代码

canActivate(route: any,state: RouterStateSnapshot): Promise<UrlTree> {
        return new Promise<UrlTree>((resolve,reject) => {
            const method = (statusParam) => {
                let tree = this.router.parseUrl(state.url);

                if (
                    statusParam === 'past_due' ||
                    statusParam === 'unpaid' ||
                    tstatusParam === 'incomplete'
                ) {
                    tree = this.router.parseUrl('/subscription');
                    tree.queryParams.subscriptionReturnUrl = state.url;
                }

                else if (
                    statusParam === 'canceled' ||
                    statusParam === 'incomplete_expired' ||
                    statusParam === null
                ) {
                    tree = this.router.parseUrl('/subscription');
                    tree.queryParams.subReturnUrl = state.url;
                    tree.queryParams.firstSub = statusParam === null;
                    console.log('...........................................');
                    console.log('statusParam === null',statusParam === null,statusParam);
                    console.log('statusParam === canceled',statusParam === 'canceled',statusParam);
                    console.log('statusParam === incomplete_expired',statusParam === 'incomplete_expired',statusParam);
                }

                resolve(tree);
            };

            if (this.status === undefined)
                this.usersService.userSubscriptionStatus().then((status) => {
                    // this.status = status;
                    console.log('Resolved Guard status is =>',status);
                    method(status);                    
                    console.log('Guard status is =>',status);
                });
            else method(this.status);
        });
    }

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。