我正在使用 @ng-idle/core 包在我的 Angular 2 应用程序中实现空闲超时(当前为 Angular 14)。超过空闲超时后,代码会将用户注销。空闲检测和注销功能已写入我的 app.component.ts 文件中。
当使用空闲时间的硬编码值编写时,代码可以完美运行。但是,我希望可以在后端配置空闲时间。因此,我编写了一个服务类,它在应用程序加载时从后端获取该值。其余代码与硬编码的空闲时间版本完全相同(除了它现在位于我的服务订阅的订阅块内)。但是,ng-idle 订阅永远不会触发。代码如下:
constructor(
private router: Router,
private idle: Idle, cd: ChangeDetectorRef,
private authSvc: AuthService,
private sessionDataSvc: SessionDataService,
private countdownSvc: CountdownService
) {
// set idle parameters
this.sessionDataSvc.getSessionProperties().subscribe(( {data} ) => {
let session_timeout = data.sessionProperties.session_idle_timeout
// set the idle and timeout values
// let session_timeout = 30;
idle.setIdle(session_timeout) // how long can they be inactive before considered idle, in seconds
idle.setTimeout(this.TIMEOUT); // how long can they be idle before considered timed out, in seconds
idle.setInterrupts(DEFAULT_INTERRUPTSOURCES); // provide sources that will "interrupt" aka provide events indicating the user is active
console.log("Setting idle timeout to " + session_timeout + " seconds")
// Some code snipped for brevity
// do something when the user has timed out
idle.onTimeout.subscribe(() => {
console.log("onTimeout called")
this.idleState = "TIMED_OUT"
this.authSvc.logout()
this.reset()
this.router.navigate(['login'], { queryParams: { reason: "Session Timeout. Please re-login" } });
});
// do something as the timeout countdown does its thing
});
console.log("Done with setting idle timeout")
});
}
reset()
{
// we'll call this method when we want to start/reset the idle process
// reset any component state and be sure to call idle.watch()
this.idle.watch();
this.idleState = "NOT_IDLE";
this.countdown = null;
this.lastPing = null;
}
注意,ng-idle 包有 4 个订阅方法 - onIdleStart、onIdleEnd、onTimeoutWarning 和 onTimeout。我故意从上面的代码中省略了前三个,以便在我的写作中简短 - 否则它们存在于代码中。 this.sessionDataSvc.getSessionProperties() 正在工作,因为 console.log 消息显示日志消息
Setting idle timeout to 30 seconds
显示在控制台日志中(与上面代码中的其他日志消息
"Done with setting idle timeout"
一样)。但没有任何 ng-idle 订阅被触发。
正如我上面提到的,如果我要注释掉这些行
this.sessionDataSvc.getSessionProperties().subscribe(( {data} ) => {
let session_timeout = data.sessionProperties.session_idle_timeout
并启用线路:
// let session_timeout = 30;
相反(这是硬编码的情况),@ng-idle 订阅按设计和记录工作。那么为什么它们不在服务订阅内?
将
subscribe
转换为另一个中的 observable
是一种不好的做法,称为“回调地狱”,为此,您需要使用 observables
中的高阶运算符(例如 RxJs
)来处理 switchMap
、 concatMap
、 mergeMap
和exhaustMap
取决于您想要实现的目标。
如果你不熟悉这些操作符,你可以阅读我不久前给出的this简短解释,或者阅读官方docs
鉴于您的代码示例,您可以像下面这样适当地重构您的逻辑,在本例中,我使用
switchMap
,但是,这又取决于需求:
...
someFunction(): void {
this.sessionDataSvc.getSessionProperties().pipe(
switchMap(({ data }) => {
// it should be const rather than let, you are not modifying its value
const sessionTimeout = data.sessionProperties.session_idle_timeout;
idle.setIdle(sessionTimeout);
idle.setTimeout(this.TIMEOUT);
idle.setInterrupts(DEFAULT_INTERRUPTSOURCES);
return idle.onTimeout; // returns an Observable
})
)
.subscribe(() => {
this.idleState = "TIMED_OUT"
this.authSvc.logout()
this.reset()
this.router.navigate(['login'], { queryParams: { reason: "Session Timeout. Please re-login" } });
});
}
reset(): void {
this.idle.watch();
this.idleState = "NOT_IDLE";
this.countdown = null;
this.lastPing = null;
}