5

我想知道HttpSession究竟什么时候会过期(与销毁不同)?

我试图弄清楚 session.getLastAccessedTime() + (session.getMaxInactiveInterval() * 1000) 是否会在每次请求带有相同的会话 ID 时为我提供会话到期的确切时间(以毫秒为单位)!

从javadocs:

长 getLastAccessedTime()

  Returns the last time the client sent a request associated with this session, as the number of milliseconds since midnight January 1, 1970 GMT, and marked by the time the container received the request.    

int getMaxInactiveInterval()

  Returns the maximum time interval, in seconds, that the servlet container will keep this session open between client accesses.  

假设我们有以下内容:
Treq1 - the time the container received the 1st request (HttpSession.lastAccessedTime)
Tresp1 - the time the container sends the 1st response
Preq1 - the time period between Treq1 and Tresp1 (the time period that the server processes the 1st request
Treq2 - the time the container received the 2nd request (HttpSession.lastAccessedTime)
Preq1req2 - the time period between Treq1 and Treq2 (the time between requests entering the container)
Presp1req2 -the time period between Tresp1 and Treq2 (the time between the 1st response exiting the container and the 2nd request entering the container)

那么现在,服务器何时将会话计算为过期?当:
1. Treq1 + maxInactiveInterval < Treq1 + Preq1req2 => maxInactiveInterval < Preq1req2
2. Tresp1 + maxInactiveInterval < Tresp1 + Presp1req2 => maxInactiveInterval < Presp1req2

这部分,the servlet container will keep this session open between client accesses有点混乱。它是指在请求进入容器之间还是在响应退出和请求进入之间?

附带说明一下我知道会话可能不会在到期的确切时间被销毁,但我还不知道它是否在容器中发生任何请求处理逻辑之前被销毁。我指的是持有过期会话 id 的请求。

亲切的问候,
暴君

4

3 回答 3

11

会话机制是Servlet 规范的一部分,该规范要求:

在 HTTP 协议中,当客户端不再处于活动状态时,没有明确的终止信号。这意味着可用于指示客户端何时不再活动的唯一机制是超时期限。

会话的默认超时时间由 servlet 容器定义,可以通过 HttpSession 接口的 getMaxInactiveInterval 方法获取。开发人员可以使用 HttpSession 接口的 setMaxInactiveInterval 方法更改此超时。这些方法使用的超时时间以秒为单位定义。根据定义,如果会话的超时期限设置为 -1,则会话将永不过期。在使用该会话的所有 servlet 都退出服务方法之前,会话失效不会生效。一旦会话失效被启动,新的请求一定不能看到该会话。

HttpSession 接口的 getLastAccessedTime 方法允许 servlet 确定在当前请求之前最后一次访问会话的时间。当作为会话的一部分的请求首先由 servlet 容器处理时,该会话被视为已访问。

假设“非活动间隔”以“lastAccessedTime”开始可能是安全的。

于 2013-01-04T15:26:24.540 回答
3

我试图弄清楚 session.getLastAccessedTime() + (session.getMaxInactiveInterval() * 1000) 是否会在每次请求带有相同的会话 ID 时为我提供会话到期的确切时间(以毫秒为单位)!

因为您只能在请求线程中访问会话对象,所以我假设您在 servlet 中有上述代码,用于通知客户端(浏览器)在下次单击之前他可以花多长时间,这可能是一个超时计数器。

我认为System.currentTimeMillis() + (session.getMaxInactiveInterval() * 1000)在这种情况下会更准确。

于 2013-01-04T09:53:39.610 回答
0

来源?

我使用“org.springframework.boot:spring-boot-starter-web:1.5.6.RELEASE” spring跟踪了两次请求并得出结论:

在您的服务处理程序(doGet、doXX 或 Controller 方法)中,到期时间将是session.getLastAccessedTime() + (session.getMaxInactiveInterval() * 1000)(2. case)

Duration:        |<---------- Preq1req2 ---------->|
Duration:        |           |<---- Presp1req2 --->|
Time    :      Treq1       Tresp1                Treq2      Tresp2
Action  : req1-->|--service--|-->resp1 ...  req2-->|--service--|-->resp2
Duration:        |<- Preq1 ->|                     |<- Preq2 ->|
                 |           |                                 | 
Set :       creationTime     |                                 |   
          lastAccessedTime   |                                 |            
                      lastAccessedTime                  lastAccessedTime

服务后更新 lastAccessedTime 时: HTTP服务后

来自 C:/Users/ssfang/.m2/repository/org/apache/tomcat/embed/tomcat-embed-core/8.5.16/tomcat-embed-core-8.5.16-sources.jar 的代码片段

package org.apache.catalina.session;
public class StandardSession implements HttpSession, Session, Serializable {
    /** The time this session was created, in milliseconds since midnight, January 1, 1970 GMT. */
    protected long creationTime = 0L;

    /**
     * We are currently processing a session expiration, so bypass
     * certain IllegalStateException tests.  NOTE:  This value is not
     * included in the serialized version of this object.
     */
    protected transient volatile boolean expiring = false;

    /** The last accessed time for this Session. */
    protected volatile long lastAccessedTime = creationTime;

    /** The session event listeners for this Session. */
    protected transient ArrayList<SessionListener> listeners = new ArrayList<>();

    /** Flag indicating whether this session is valid or not. */
    protected volatile boolean isValid = false;

    /** The current accessed time for this session. */
    protected volatile long thisAccessedTime = creationTime;


    /** The access count for this session. */
    protected transient AtomicInteger accessCount = null;

    /**
     * The maximum time interval, in seconds, between client requests before the servlet container may
     * invalidate this session.  A negative time indicates that the session should never time out.
     */
    protected volatile int maxInactiveInterval = -1;

    /**
     * Return the idle time from last client access time without invalidation check
     * @see #getIdleTime()
     */
    @Override
    public long getIdleTimeInternal() {
        long timeNow = System.currentTimeMillis();
        long timeIdle;
        if (LAST_ACCESS_AT_START) {
            timeIdle = timeNow - lastAccessedTime;
        } else {
            timeIdle = timeNow - thisAccessedTime;
        }
        return timeIdle;
    }

    /**
     * Set the creation time for this session.  This method is called by the
     * Manager when an existing Session instance is reused.
     *
     * @param time The new creation time
     */
    @Override
    public void setCreationTime(long time) {
        this.creationTime = time;
        this.lastAccessedTime = time;
        this.thisAccessedTime = time;
    }

    /** Return the <code>isValid</code> flag for this session. */
    @Override
    public boolean isValid() {
        if (!this.isValid) {
            return false;
        }
        if (this.expiring) {
            return true;
        }
        if (ACTIVITY_CHECK && accessCount.get() > 0) {
            return true;
        }
        if (maxInactiveInterval > 0) {
            int timeIdle = (int) (getIdleTimeInternal() / 1000L);
            if (timeIdle >= maxInactiveInterval) {
                expire(true);
            }
        }
        return this.isValid;
    }
}

获取会话前检查会话是否有效

获取会话前检查会话是否有效

一个后台线程扫描所有会话是否已过期。

后台线程扫描会话

于 2017-11-15T10:19:57.157 回答