如何解决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 首先运行
使用接受参数 method
的 statusParam
函数更新您的代码
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 举报,一经查实,本站将立刻删除。