如何显示足够智能以处理多个打开的浏览器或选项卡的会话超时警告

Posted

技术标签:

【中文标题】如何显示足够智能以处理多个打开的浏览器或选项卡的会话超时警告【英文标题】:How can you display a session timeout warning that is smart enough to handle multiple open browsers or tabs 【发布时间】:2010-09-26 16:52:36 【问题描述】:

我使用 javascript 实现了会话超时警告,它只是询问用户是否要延长会话或注销。问题在于,这是针对高级用户通常会同时打开多个浏览器窗口或选项卡的 Intranet 门户的应用程序。目前,系统会提示他们即将从每个浏览器窗口中注销。如何让代码更智能地检测到他们正在积极使用另一个浏览器会话?

【问题讨论】:

这是一个有趣且非常实用的问题。我会留意对此的回应,因为我没有立即答复:) 不知道为什么这被否决了。 是的,我也很惊讶。我投了赞成票,而且由于乔尔是 SO 的新手,他没有做错任何事来阻止他通过投票:) Joel,我正在寻找您已有的解决方案。我确实希望所有浏览器都能收到警告并注销。你介意分享你的代码和方法吗? 警告:这是我在编程的黑暗时代写的。 dl.dropbox.com/u/203098/sessiontimeout.js 【参考方案1】:

您必须使用 Ajax 检查服务器上的会话状态,并跟踪用户拥有的所有打开的会话/窗口。然后,您就可以只针对其中一个可用会话发出注销警告。

回应您的评论:

不要使用内置的会话机制,使用服务器端的持久数组或数据库日志来设计自己的。

不,HTTP 请求中没有任何内容告诉您打开了多少浏览器,但您可以在用户打开每个浏览器窗口时分配您自己的 sessionID cookie。对服务器进行 Ajax 调用,查看用户是否超时,如果您是会话日志中最低(或最后)的条目,那么您就是收到警告的浏览器。

【讨论】:

2 个想法:1) 如何在不实际扩展会话的情况下检查 .NET 应用程序的会话状态? 2)实际上有没有办法告诉用户有多少个浏览器窗口? http 请求中没有任何内容告诉您这一点 在用户执行操作时调用更新会话的函数,在检查会话状态时不要调用该函数。您可以根据代理字符串检测打开了多少个浏览器,不要以为您可以检测到每个浏览器的窗口/选项卡。 我不明白它是如何工作的。此外,如果他们使用不同的浏览器(如 IE 和 FF),甚至是同一浏览器的不同实例,那么他们有不同的会话,所以这不是问题。【参考方案2】:

这行得通吗?

存储一个 Javascript cookie 并检查以确定会话是否已在另一个选项卡中扩展?

看起来这确实有效......

【讨论】:

4 年后,这看起来仍然是正确的答案,至少对于 ASP.NET。问题是您需要客户端和服务器端方法的组合,我认为您无法在服务器端获得它(因为您可以跟踪登录/退出或会话开始/结束,但不能跟踪客户端活动服务器不知道的)。因此,我认为您需要的正是您在这里的建议。完成后我会发布它。【参考方案3】:

您不能指望所有选项卡/窗口都属于同一个会话,因为它们可能会产生并包含在不同的进程中,而您对此没有太多控制权。

但如果您的代码引用了 Javascript cookie,您可以通过回发(同步或异步 AJAX)检查您的伪会话状态。但是,您依赖于在用户浏览器上启用的 cookie。

【讨论】:

【参考方案4】:

安装@ng-idle @ng-idle 可通过 NPM 获得。通过运行安装它:

npm install --save @ng-idle/core @ng-idle/keepalive angular2-moment

设置您的应用程序模块 打开 src/app/app.module.ts 并使用

导入 Ng2IdleModule
import  BrowserModule  from '@angular/platform-browser';
import  NgModule  from '@angular/core';
import  FormsModule  from '@angular/forms';
import  HttpModule  from '@angular/http';

import  NgIdleKeepaliveModule  from '@ng-idle/keepalive'; // this includes the core NgIdleModule but includes keepalive providers for easy wireup

import  MomentModule  from 'angular2-moment'; // optional, provides moment-style pipes for date formatting

import  AppComponent  from './app.component';

@NgModule(
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    FormsModule,
    HttpModule,
    MomentModule,
    NgIdleKeepaliveModule.forRoot()
  ],
  providers: [],
  bootstrap: [AppComponent]
)
export class AppModule  

然后在component.ts中

import  Component  from '@angular/core';

import Idle, DEFAULT_INTERRUPTSOURCES from '@ng-idle/core';
import Keepalive from '@ng-idle/keepalive';

@Component(
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
)
export class AppComponent 

    currentPath: String;

    idleState = 'Not started.';
    timedOut = false;
    lastPing?: Date = null;

    constructor(private idle: Idle, private keepalive: Keepalive, location: Location, router: Router) 

        // sets an idle timeout of 5 seconds, for testing purposes.
        idle.setIdle(5);

        // sets a timeout period of 5 seconds. after 10 seconds of inactivity, the user will be considered timed out.
        idle.setTimeout(5);

        // sets the default interrupts, in this case, things like clicks, scrolls, touches to the document
        idle.setInterrupts(DEFAULT_INTERRUPTSOURCES);

        idle.onIdleEnd.subscribe(() => this.idleState = 'No longer idle.');

        idle.onTimeout.subscribe(() => 
            this.idleState = 'Timed out!';
            this.timedOut = true;
        );

        idle.onIdleStart.subscribe(() => this.idleState = 'You\'ve gone idle!');
        idle.onTimeoutWarning.subscribe((countdown) => this.idleState = 'You will time out in ' + countdown + ' seconds!');

        // Sets the ping interval to 15 seconds
        keepalive.interval(15);

        keepalive.onPing.subscribe(() => this.lastPing = new Date());

        // Lets check the path everytime the route changes, stop or start the idle check as appropriate.
        router.events.subscribe((val) => 

            this.currentPath = location.path();
            if(this.currentPath.search(/authentication\/login/gi) == -1)
                idle.watch();
            else
                idle.stop();

        );
    

    reset() 
        this.idle.watch();
        this.idleState = 'Started.';
        this.timedOut = false;
    

【讨论】:

以上是关于如何显示足够智能以处理多个打开的浏览器或选项卡的会话超时警告的主要内容,如果未能解决你的问题,请参考以下文章

在 vue.js 小部件中打开多个选项卡时找出活动选项卡的方法

打开多个选项卡的自动注销

如何查询浏览器的User Agent是啥

如何使用 Intent 打开显示“组”选项卡的联系人?

如果它已经在浏览器中打开,如何打开同一个选项卡的 url

javascript如何实现浏览器选项卡的切换?