关闭窗口时如何注销我的应用程序?

时间:2012-11-15 15:19:28

标签: javascript ajax jsp servlets

在我的聊天应用程序中,我有退出按钮,它运行正常。

现在我还需要在关闭浏览器窗口时注销该应用程序..我怎样才能实现这一目标...

提前致谢...

10 个答案:

答案 0 :(得分:10)

对于客户端,没有确切的方法可以做到这一点。退出页面时不会触发任何事件。应该使用服务器上的Session End事件来完成。

您可以尝试使用onbeforeunload或unload,但竞争条件会阻止这种情况发生。并且它们不会因浏览器崩溃,丢失互联网连接等而触发

答案 1 :(得分:6)

我最近在angularJS应用程序中处理了这个问题 - 主要问题是如果你刷新我不想让你退出,但我确实想要关闭标签..用onbeforeunload进行Ajax请求/ onunload不保证等待响应,所以这是我的解决方案:

我在登录时设置了一个sessionStorage cookie,这只是一个bool - 当我得到登录响应时设置为true

sessionStorage.setItem('activeSession', 'true');

显然,在注销时,我们将此标志设置为false

当控制器初始化或使用window.onload(在我的app.js文件中)时 - 我检查这个activeSession bool ..如果它是false,我有这个小if语句 - 如果条件满足,我调用我的注销方法 ONLOAD 而不是onunload

   var activeSession = sessionStorage.activeSession;
    if (sessionStorage.loggedOutOnAuth) {
        console.log('Logged out due to expiry already')
    }
    else if (!activeSession) {
        sessionStorage.loggedOutOnAuth = true;
        _logout()
    }

基本上," loggedOutAuth" bool让我知道因为sessionStorage中没有activeSession所以我刚刚在页面加载时过期了你所以你不会陷入循环中

这对我来说是一个很好的解决方案,因为我不想实现心跳/ websocket

答案 2 :(得分:4)

将您的退出代码添加到on onunload事件。

window.onunload = function () {
    //logout code here...
}

在JQuery中,您可以使用.unload()函数。请记住,您没有太多时间,因此您可能会发送Ajax请求,但结果可能无法到达客户端。

另一个技巧是打开一个小的新窗口并处理那里的注销。

window.open("logout url","log out","height=10,width=10,location=no,menubar=no,status=no,titlebar=no,toolbar=no",true);

如果要禁用关闭窗口(或至少警告用户),可以使用以下代码:

window.onbeforeunload = function(event) {
    //if you return anything but null, it will warn the user.
    //optionally you can return a string which most browsers show to the user as the warning message.
    return true;
}

另一个技巧是每隔几秒钟对客户端进行一次ping操作。如果没有回复,则假设用户已关闭窗口,浏览器已崩溃或网络问题无论如何都已结束聊天会话。在客户端,如果您没有收到此ping包,则可以假设网络连接或服务器出现问题,您可以显示注销警告(并可选择让用户再次登录)。

答案 3 :(得分:1)

某些网站正在使用以下脚本来检测窗口是否已关闭。

if(window.screenTop > 10000)
alert("Window is closed");
else
alert("Window stillOpen");

您需要添加正确的操作,而不是alert()

还要看一下HERE - 我认为这是检测窗口关闭所需要的东西

答案 4 :(得分:1)

我得到了解决方案,

window.onunload = function () {
    //logout code here...
}

感谢所有支持我的人......

答案 5 :(得分:1)

另一种方法是某种“keepalive”:浏览器页面每隔一分钟就用一个小的ajax请求“ping”服务器。如果服务器没有获得常规ping,会话将关闭,无法再使用。

作为优化,如果我们在过渡期间向服务器发出另一个请求,则可以跳过ping。

优点:

  • 仍适用于打开多个窗口
  • F5 / refresh
  • 没问题
  • 可以向服务器提供一些使用情况统计信息

缺点:

  • 当窗口关闭时,用户退出前会有延迟
  • 使用少量网络带宽
  • 服务器上的额外负载
  • 用户可能会不断关注该网页“打电话回家”
  • 更难实施

我从来没有在网络应用中实际做到这一点,也不确定我是否愿意;只是把它作为替代品。对于聊天应用来说,这似乎是一个不错的选择,服务器确实需要知道你是否还在那里。

而不是轮询/ ping,另一种可能性是在页面打开时保持“长时间运行的请求”打开。聊天应用需要一些这样的套接字来接收新消息和通知。如果页面关闭,套接字也会关闭,服务器可以注意到它已被关闭。然后等待客户端建立新套接字的短暂时间,如果不是,我们假设页面已关闭并删除会话。这将需要服务器上一些稍微不寻常的软件。

答案 6 :(得分:0)

我在这里遇到了这个问题,我得到了一个不同的解决方案:

    checkSessionTime();
    $interval(checkSessionTime, 2000);
    function checkSessionTime() {
        var now = (new Date()).getTime();
        if (!$localStorage.lastPing) {
            $localStorage.lastPing = now;
        }

        if ($localStorage.lastPing < now - 5000) {
            $localStorage.lastPing = undefined;
            AuthService.logout();
        } else {
            $localStorage.lastPing = now;
        }
    }

我喜欢这个解决方案,因为它不会增加ping服务器的开销,也不依赖于窗口卸载事件。此代码放在$app.run

我正在使用带有JWT身份验证的角度,这种方式让我注销只是意味着摆脱身份验证令牌。但是,如果您需要完成会话服务器端,您可以构建Auth服务以在完成会话时执行一次ping操作,而不是继续ping以保持会话活动。

这解决了我的情况,因为我的意图只是为了防止不需要的用户在关闭标签并离开PC时访问某人帐户。

答案 7 :(得分:0)

经过大量搜索后,我在javascript和服务器端代码中编写了以下自定义代码,用于c#中的会话终止。

如果同一个网站在多个标签页面中打开,则会扩展以下代码,以便会话处于活动状态,直到网站的一个标签页打开

//Define global varible 
var isCloseWindow = false;

 //Jquery page load function to register the events

 $(function () {
        //function for onbeforeuload
        window.onbeforeunload = ConfirmLeave;
        //function for onload
        window.onload = ConfirmEnter;

        //mouseover for div which spans the whole browser client area 
        $("div").on('mouseover', (function () {
        //for postback from the page make isCloseWindow global varible to false
            isCloseWindow = false;
        }));
        //mouseout event
        $("div").on('mouseout', (function () {
     //for event raised from tabclose,browserclose etc. the page make isCloseWindow global varible to false
            isCloseWindow = true;
        }));
    });
     //Key board events to track  the  browser tab or browser closed by ctrl+w or alt+f4 key combination
    $(document).keydown(function (e) {
        if (e.key.toUpperCase() == "CONTROL") {
            debugger;
            isCloseWindow = true;
        }
        else if (e.key.toUpperCase() == "ALT") {
            debugger;
            isCloseWindow = true;
        }
        else {
            debugger;
            isCloseWindow = false;
        }
    });

    function ConfirmEnter(event) {
        if (localStorage.getItem("IsPostBack") == null || localStorage.getItem("IsPostBack") == "N") {
            if (localStorage.getItem("tabCounter") == null || Number(localStorage.getItem("tabCounter")) == 0) {
                //cookie is not present
                localStorage.setItem('tabCounter', 1);

            } else {
                localStorage.setItem('tabCounter', Number(localStorage.getItem('tabCounter')) + 1);
            }
        }
        localStorage.setItem("IsPostBack", "N");
    }
    function ConfirmLeave(event) {
        if (event.target.activeElement.innerText == "LOGOUT") {
            localStorage.setItem('tabCounter', 0);
            localStorage.setItem("IsPostBack", "N");
        } else {
            localStorage.setItem("IsPostBack", "Y");
        }
        if ((Number(localStorage.getItem('tabCounter')) == 1 && isCloseWindow == true)) {
            localStorage.setItem('tabCounter', 0);
            localStorage.setItem("IsPostBack", "N");
            **Call Web Method Kill_Session using jquery ajax call**
        } else if (Number(localStorage.getItem('tabCounter')) > 1 && isCloseWindow == true) {
            localStorage.setItem('tabCounter', Number(localStorage.getItem('tabCounter')) - 1);
        }
    }

 //C# server side WebMethod
 [WebMethod]
  public static void Kill_Session()
    {
        HttpContext.Current.Session.Abandon();
    }

答案 8 :(得分:0)

对于此问题,我尝试了2种解决方案: window.onbeforeunload 事件和 sessionStorage

  • 由于 window.onbeforeunload 不仅用于关闭浏览器,而且还用于重定向,选项卡刷新,新选项卡,所以它不是一个可靠的解决方案。另外,在某些情况下该事件没有发生:通过命令行关闭浏览器,关闭计算机

  • 我切换为使用sessionStorage。当用户登录时,我将sessionStorage变量设置为'true';加载应用程序时,我将检查该变量是否存在,否则,将强制用户登录。但是,我需要在各个选项卡之间共享sessionStorage变量,以便在用户打开文件时不会强制用户登录。在同一个浏览器实例中的新标签页上,我能够利用storage event来做到这一点; here

  • 是一个很好的例子

答案 9 :(得分:0)

tabOrBrowserStillAliveInterval;

constructor() {
  // system should logout if the browser or last opened tab was closed (in 15sec after closing)
  if (this.wasBrowserOrTabClosedAfterSignin()) {
    this.logOut();
  }

  // every 15sec update browserOrTabActiveTimestamp property with new timestamp
  this.setBrowserOrTabActiveTimestamp(new Date());
  this.tabOrBrowserStillAliveInterval = setInterval(() => {
    this.setBrowserOrTabActiveTimestamp(new Date());
  }, 15000);
}

signin() {
  // ...
  this.setBrowserOrTabActiveTimestamp(new Date());
}

setBrowserOrTabActiveTimestamp(timeStamp: Date) {
  localStorage.setItem(
    'browserOrTabActiveSessionTimestamp',
    `${timeStamp.getTime()}`
  );
}

wasBrowserOrTabClosedAfterSignin(): boolean {
  const value = localStorage.getItem('browserOrTabActiveSessionTimestamp');

  const lastTrackedTimeStampWhenAppWasAlive = value
    ? new Date(Number(value))
    : null;
  const currentTimestamp = new Date();
  const differenceInSec = moment(currentTimestamp).diff(
    moment(lastTrackedTimeStampWhenAppWasAlive),
    'seconds'
  );

  // if difference between current timestamp and last tracked timestamp when app was alive
  // is more than 15sec (if user close browser or all opened *your app* tabs more than 15sec ago)
  return !!lastTrackedTimeStampWhenAppWasAlive && differenceInSec > 15;
}

工作原理: 如果用户关闭浏览器或关闭所有打开的您的应用标签,则在 15 秒超时后 - 将触发注销。

  • 它适用于打开多个窗口
  • 没有额外的服务器负载
  • F5 / 刷新没问题

浏览器限制是我们在注销前需要 15 秒超时的原因。由于浏览器无法区分以下情况:浏览器关闭、选项卡关闭和选项卡刷新。所有这些操作都被浏览器视为相同的操作。因此,15 秒超时就像一种解决方法,仅捕获浏览器关闭或关闭所有打开的您的应用 选项卡(并跳过刷新/F5)。