Java:为什么在关闭选项卡或浏览器时不会破坏 http 会话?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/706224/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 18:34:07  来源:igfitidea点击:

Java:Why http session is not destroyed when tab or browser is closed?

javasession

提问by Flueras Bogdan

I have the following implementation of HttpSessionlistener

我有以下 HttpSessionlistener 的实现

public class SessionListener implements HttpSessionAttributeListener, HttpSessionListener {


public void attributeAdded(HttpSessionBindingEvent event) {
   ...

}


public void attributeRemoved(HttpSessionBindingEvent event) {

    ...
}

public void attributeReplaced(HttpSessionBindingEvent event) {

}

//HttpSesion creation & destruction
public void sessionCreated(HttpSessionEvent event) {
    HttpSession session = event.getSession();
    //log created time


}

public void sessionDestroyed(HttpSessionEvent event) {
    HttpSession session = event.getSession();
    long destroyedTime = System.currentTimeMillis();
    //log destroyed time

}

}

}

Basically i log the session creation and destruction time. But if the session is long (default to 30 minutes), and user closes browser meanwhile, the

基本上我记录会话创建和销毁时间。但是如果会话很长(默认为 30 分钟),并且用户同时关闭浏览器,则

sessionDestroyed 

is not called ?

不叫?

Why is that ? Is there a workaround to log exactly the when the session was destroyed (when user closes the browser)? Should'nt be this be the browser's problem, to kill the session when it is closed ?

这是为什么 ?是否有一种解决方法可以准确记录会话被销毁的时间(当用户关闭浏览器时)?这不应该是浏览器的问题,在会话关闭时终止会话吗?

Is there any interface that i have to implement for this to work ?

有没有我必须实现的接口才能工作?

Thank you !

谢谢 !

采纳答案by Jon Skeet

How would the server know when the browser is closed or the tab closed? At that point the browser doesn't send anything to the server.

服务器如何知道浏览器何时关闭或选项卡何时关闭?此时浏览器不会向服务器发送任何内容。

This is a fundamental part of HTTP - it's a request/response protocol, not a "permanently open conversation" where you can tell if one party leaves the conversation. Think of it as a series of telegrams rather than a phone call - and you can't tell when you've received the last telegram you're going to get.

这是 HTTP 的基本部分 - 它是一种请求/响应协议,而不是“永久开放的对话”,您可以在其中判断一方是否离开对话。把它想象成一系列的电报而不是一个电话——你不知道你什么时候收到了你将要收到的最后一份电报。

You'll need to design your way round this - to avoid needingto know when the browser has been closed. There are some ugly hacks to work around it - making AJAX poll the server with a heartbeat message, for example - but changing the design is a better solution.

您需要设计自己的方式 - 避免需要知道浏览器何时关闭。有一些丑陋的技巧可以解决这个问题——例如,让 AJAX 使用心跳消息轮询服务器——但改变设计是一个更好的解决方案。

回答by David Waters

With out a lot of work the browser does not inform the server that the window is closed, therefore Java can not know when to destroy the session. Hence the time out is in place and is the first the server knows that this session can be distroyed.

由于没有大量工作,浏览器不会通知服务器窗口已关闭,因此 Java 无法知道何时销毁会话。因此超时已经到位,并且是服务器第一次知道这个会话可以被破坏。

You could try and play an ajax call on the javascript event document.onunload https://developer.mozilla.org/en/DOM/window.onunloadbut you will need to be sure that the user is not still within your site when you do this.

您可以尝试在 javascript 事件 document.onunload https://developer.mozilla.org/en/DOM/window.onunload上播放 ajax 调用, 但您需要确保用户不在您的站点内做这个。

回答by bruno conde

Session objects live in the server and are controlled by the server. Only the server can create or destroy sessions. So if the client is closed the session lives until it expires. The client can only suggest to the server that it can destroy some session. This request must be explicit somehow. Hence, when you close a browser window, there's no implicit request to the server informing that it must destroy a given session.

会话对象存在于服务器中并由服务器控制。只有服务器可以创建或销毁会话。因此,如果客户端关闭,则会话会一直存在,直到过期。客户端只能向服务器建议它可以销毁某个会话。这个请求必须以某种方式明确。因此,当您关闭浏览器窗口时,没有对服务器的隐式请求通知它必须销毁给定的会话。

回答by Eric Wendelin

If you need the session to be destroyed when a browser window/tab is closed you might attach a JavaScript handler to the onunload event that makes some sort of AJAX call to a resource that call kill the session.

如果您需要在浏览器窗口/选项卡关闭时销毁会话,您可以将 JavaScript 处理程序附加到 onunload 事件,该事件对调用终止会话的资源进行某种 AJAX 调用。

Note that the onunload event does not always fire so it's not totally trustworthy. One trusty way might be to use a "heartbeat" system.

请注意, onunload 事件并不总是会触发,因此它并不完全值得信赖。一种可靠的方法可能是使用“心跳”系统。

回答by Eric Wendelin

As Eric mentioned the unload event on the browser can call a javascript function, which in turn can access an url through a servlet that logs you out. You need not wait for the actual response from the servlet.

正如 Eric 提到的,浏览器上的卸载事件可以调用一个 javascript 函数,该函数又可以通过一个 servlet 访问一个 url,从而将您注销。您无需等待来自 servlet 的实际响应。

The web browser interacts with the server through the http protocol and that is stateless.

Web 浏览器通过 http 协议与服务器交互,这是无状态的。

回答by ramayac

NOTE:As jwentingcommented below, this it's not 100% safe at all. If the the onunload event does not get triggered by a closing event of the browser tab or window, then this would fail.

注意:正如jwenting在下面评论的那样,这根本不是 100% 安全的。如果 onunload 事件没有被浏览器选项卡或窗口的关闭事件触发,那么这将失败。

I had the same problem, and solve it using an intrusive JavaScript event:

我遇到了同样的问题,并使用侵入性 JavaScript 事件解决了它:

window.onunload

Let me briefly explain, lets say you have a JavaScript function that post, using jQuery, the current Session ID to that Servlet to invalidate it, like this:

让我简要解释一下,假设您有一个 JavaScript 函数,该函数使用 jQuery 将当前会话 ID 发布到该 Servlet 以使其无效,如下所示:

function safeexit(){
   $.post("/SessionKillServlet", { SID = <%=session.getId()%> }, function(data){});
}

To call that function, you just need to bind it like these:

要调用该函数,您只需要像这样绑定它:

window.onunload =  safeexit;  //without the ()

Now, safeexit method will be called when the TAB or BROWSER WINDOW gets closed (or in a redirection).

现在,当 TAB 或 BROWSER WINDOW 关闭(或重定向)时,将调用 safeexit 方法。

回答by walid fekkak

you can just verify if your session user , aren't null like :

您可以验证您的会话用户是否为空,例如:

if (session.getAttribute("user") != null )
   sessionsetAttribute("user","null");

回答by Dharmendrasinh Chudasama

there is some hacks for knows following code for destroy session when user closes browser

当用户关闭浏览器时,有一些技巧可以了解以下用于销毁会话的代码

client side:

客户端:

<script src="jquery path"></script>
<script>
  window.onunload = function(){ $.get("${request.contextPath}/logout"); }
</script>

server side: create request mapping for "/logout"

服务器端:为“/logout”创建请求映射

public void doGet(HttpServletRequest request, HttpServletResponse) {
  request.getSession().invalidate();
  System.out.println('destroy from logout on unload browser');
}

Following code is optional

use session listener when want to know when session destroyed

以下代码是可选的

想知道会话何时销毁时使用会话侦听器

//    in class

import javax.servlet.*;
import javax.servlet.http.*;
public class SesListener implements HttpSessionListener {
  public void sessionCreated(HttpSessionEvent se) {
   System.out.println("Session created...");
  }

  public void sessionDestroyed(HttpSessionEvent se) {
    System.out.println("Session destroyed...");
  }
}

//-----------------------------------------

// in web.xml
<listener>
   <listener-class>SesListener</listener-class>
</listener>