当浏览器或选项卡关闭时关闭/结束会话。

37

请问有人能告诉我如何在用户关闭浏览器时关闭/终止会话吗?我的asp.net web应用程序使用stateserver模式。使用onbeforeunload方法不太合适,因为它在用户刷新页面时触发。

9个回答

37
你无法做到。HTTP是一种无状态协议,因此你无法知道用户是否已关闭他们的浏览器还是只是坐在打开的浏览器窗口不做任何操作。
这就是为什么会话有一个超时时间 - 你可以尝试缩短超时时间以更快地关闭不活动的会话,但这可能会导致合法用户的会话提前超时。

21
Facebook 和 Gmail 都这么做,有人知道它们是如何实现的吗? - NexusRex
12
您可以设置一个会话cookie,在浏览器关闭时过期。这不会使会话在服务器端过期,但是浏览器将不再拥有该令牌。 - Michael Stum
古老的问题/答案,但浏览器会恢复会话cookie。自Chrome 19(约2012年)以来,Chrome就已经实现了这一功能。 - ZachB

7

正如所说的,浏览器关闭时不会通知服务器。

不过,有一些方法可以接近这种行为。您可以放置一个小型的AJAX脚本,定期更新服务器,以表明浏览器是打开状态。您应该配合用户操作触发的功能,这样您就可以超时空闲会话以及已关闭的会话。


6

如你所说,当用户单击链接或刷新页面时,事件窗口window.onbeforeunload会触发,因此它不是一个好的结束会话的事件。

http://msdn.microsoft.com/en-us/library/ms536907(VS.85).aspx描述了所有触发window.onbeforeonload的情况。(IE)

但是,您可以在页面上放置一个JavaScript全局变量,以识别不应触发注销的操作(例如通过从onbeforeonload进行AJAX调用)。

下面的脚本依赖于JQuery。

/*
* autoLogoff.js
*
* Every valid navigation (form submit, click on links) should
* set this variable to true.
*
* If it is left to false the page will try to invalidate the
* session via an AJAX call
*/
var validNavigation = false;

/*
* Invokes the servlet /endSession to invalidate the session.
* No HTML output is returned
*/
function endSession() {
   $.get("<whatever url will end your session>");
}

function wireUpEvents() {

  /*
  * For a list of events that triggers onbeforeunload on IE
  * check http://msdn.microsoft.com/en-us/library/ms536907(VS.85).aspx
  */
  window.onbeforeunload = function() {
      if (!validNavigation) {
         endSession();
      }
  }

  // Attach the event click for all links in the page
  $("a").bind("click", function() {
     validNavigation = true;
  });

  // Attach the event submit for all forms in the page
  $("form").bind("submit", function() {
     validNavigation = true;
  });

}

// Wire up the events as soon as the DOM tree is ready
$(document).ready(function() {
    wireUpEvents();  
});

此脚本可包含在所有页面中

<script type="text/javascript" src="js/autoLogoff.js"></script>

让我们来看一下这段代码:

  var validNavigation = false;

  window.onbeforeunload = function() {
      if (!validNavigation) {
         endSession();
      }
  }

  // Attach the event click for all links in the page
  $("a").bind("click", function() {
     validNavigation = true;
  });

  // Attach the event submit for all forms in the page
  $("form").bind("submit", function() {
     validNavigation = true;
  });

全局变量定义在页面级别。如果该变量未设置为true,则事件windows.onbeforeonload将终止会话。

事件处理程序附加到页面中的每个链接和表单,以将此变量设置为true,从而防止用户仅提交表单或单击链接时终止会话。

function endSession() {
   $.get("<whatever url will end your session>");
}

会话将在用户关闭浏览器/选项卡或导航离开时终止。在这种情况下,全局变量未设置为true,脚本将执行AJAX调用到您想要结束会话的任何URL。
此解决方案与服务器端技术无关。尽管没有经过详尽的测试,但在我的测试中似乎运行良好。

4
需要注意的是,你必须将它变成一个“同步”的Ajax请求,否则它几乎不可能被触发。当然,同步的Ajax请求很丑陋,会完全占用浏览器的用户界面。 - T.J. Crowder
@T.J. Crowder:当你的服务器出现问题,典型的响应时间超过5秒时,丑陋是一个轻描淡写的词语。 - Andy E
1
有效的评论。那么,使用非常小的超时时间进行同步 AJAX 调用呢?请注意,所提出的解决方案并不旨在解决所有孤立会话的问题。它只能覆盖其中的一部分(用户主动关闭浏览器且注销 URL 响应非常快)。 - Daniel Melo
1
如果用户使用浏览器的后退/前进按钮刷新页面或导航,这仍将不正确地终止会话。 - Simon Lieschke
我建议您添加以下代码://this code will handle the F5 or Ctrl+F5 key //need to handle more cases like ctrl+R whose codes are not listed here document.onkeydown = checkKeycode function checkKeycode(e) { var keycode; if (window.event) keycode = window.event.keyCode; else if (e) keycode = e.which; if(keycode == 116) { validNavigation = true; } } 就像Saravanakumar 写的 - 这将防止在刷新时终止会话。 - BornToCode
使用 GET 请求来销毁会话?我认为 DELETE 或至少是 POST 更合适。 - scaryguy

3

现在虽然不是完美的解决方案,但是是最好的解决方案:

var spcKey = false;
var hover = true;
var contextMenu = false;

function spc(e) {
    return ((e.altKey || e.ctrlKey || e.keyCode == 91 || e.keyCode==87) && e.keyCode!=82 && e.keyCode!=116);
}

$(document).hover(function () {
    hover = true;
    contextMenu = false;
    spcKey = false;
}, function () {
    hover = false;
}).keydown(function (e) {
    if (spc(e) == false) {
        hover = true;
        spcKey = false;
    }
    else {
        spcKey = true;
    }
}).keyup(function (e) {
    if (spc(e)) {
        spcKey = false;
    }
}).contextmenu(function (e) {
    contextMenu = true;
}).click(function () {
    hover = true;
    contextMenu = false;
});

window.addEventListener('focus', function () {
    spcKey = false;
});
window.addEventListener('blur', function () {
    hover = false;
});

window.onbeforeunload = function (e) {
    if ((hover == false || spcKey == true) && contextMenu==false) {
        window.setTimeout(goToLoginPage, 100);
        $.ajax({
            url: "/Account/Logoff",
            type: 'post',
            data: $("#logoutForm").serialize(),
        });
        return "Oturumunuz kapatıldı.";
    }
    return;
};

function goToLoginPage() {
    hover = true;
    spcKey = false;
    contextMenu = false;
    location.href = "/Account/Login";
}

3
我是这样做的:

$(window).bind('unload', function () {
    if(event.clientY < 0) {  
        alert('Thank you for using this app.');
        endSession(); // here you can do what you want ...
    }  
    });
window.onbeforeunload = function () {
    $(window).unbind('unload');
    //If a string is returned, you automatically ask the 
    //user if he wants to logout or not...
    //return ''; //'beforeunload event'; 
    if (event.clientY < 0) {
        alert('Thank you for using this service.');
        endSession();
    }  
}  

1
如果用户按下ALT+F4会怎样? - Sameh Deabes

3
请参考以下步骤:

  1. First create a page SessionClear.aspx and write the code to clear session
  2. Then add following JavaScript code in your page or Master Page:

    <script language="javascript" type="text/javascript">
        var isClose = false;
    
        //this code will handle the F5 or Ctrl+F5 key
        //need to handle more cases like ctrl+R whose codes are not listed here
        document.onkeydown = checkKeycode
        function checkKeycode(e) {
        var keycode;
        if (window.event)
        keycode = window.event.keyCode;
        else if (e)
        keycode = e.which;
        if(keycode == 116)
        {
        isClose = true;
        }
        }
        function somefunction()
        {
        isClose = true;
        }
    
        //<![CDATA[
    
            function bodyUnload() {
    
          if(!isClose)
          {
                  var request = GetRequest();
                  request.open("GET", "SessionClear.aspx", true);
                  request.send();
          }
            }
            function GetRequest() {
                var request = null;
                if (window.XMLHttpRequest) {
                    //incase of IE7,FF, Opera and Safari browser
                    request = new XMLHttpRequest();
                }
                else {
                    //for old browser like IE 6.x and IE 5.x
                    request = new ActiveXObject('MSXML2.XMLHTTP.3.0');
                }
                return request;
            } 
        //]]>
    </script>
    
  3. Add the following code in the body tag of master page.

    <body onbeforeunload="bodyUnload();" onmousedown="somefunction()">
    

2

如果要关闭浏览器,您可以将以下代码放入web.config文件中:

<system.web>
    <sessionState mode="InProc"></sessionState>
 </system.web>

当浏览器关闭时,它会销毁您的会话,但在关闭选项卡时不起作用。

2

当机器由于断电等原因意外关闭时,无法销毁会话变量。只有在用户长时间空闲或适当注销时才能实现。


2
服务器端,如果您处于闲置状态或者机器关闭了,都不会有任何影响。客户端,您无法控制会话变量。 - Alex

1

Use this:

 window.onbeforeunload = function () {
    if (!validNavigation) {
        endSession();
    }
}

jsfiddle

防止F5刷新、表单提交、输入框点击和浏览器或标签关闭时关闭/终止会话,已在ie8+和现代浏览器中进行测试,享受吧!


1
请注意,此解决方案仅在用户允许执行JavaScript的情况下才有效,因此这可能是一个严重的安全问题。 - flumingo
对于那些想要从今天开始使用这个解决方案的人来说,这段代码无法处理浏览器刷新按钮、后退按钮、前进按钮以及在浏览器的URL栏中按下回车键等事件。当任何上述事件发生时,注销将被触发,同时也会在标签页/浏览器关闭时触发。 - NAK

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接