request.getSession(false) causes java.lang.Illegal

2019-04-09 19:31发布

问题:

When I try to get the session from the request, it causes a null pointer exception if the session is expired. Given below is a part of the code. I get exception on the third line.

public void doFilter(ServletRequest req, ServletResponse res,FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpReq = (HttpServletRequest) req;
HttpSession session = httpReq.getSession(false);

And here is the stacktrace :

java.lang.IllegalStateException: getLastAccessedTime: Session already invalidated
at org.apache.catalina.session.StandardSession.getLastAccessedTime(StandardSession.java:423)
at org.apache.catalina.session.StandardSessionFacade.getLastAccessedTime(StandardSessionFacade.java:84)
at com.myapp.admin.CustomerContext.valueUnbound(CustomerContext.java:806)
at org.apache.catalina.session.StandardSession.removeAttributeInternal(StandardSession.java:1686)
at org.apache.catalina.session.StandardSession.expire(StandardSession.java:801)
at org.apache.catalina.session.StandardSession.isValid(StandardSession.java:576)
at org.apache.catalina.connector.Request.doGetSession(Request.java:2386)
at org.apache.catalina.connector.Request.getSession(Request.java:2120)
at org.apache.catalina.connector.RequestFacade.getSession(RequestFacade.java:833)
at com.myapp.ui.web.filter.ApplicationSessionFilter.doFilter(ApplicationSessionFilter.java:45)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:237)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:167)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at com.myapp.ui.web.filter.ErrorFilter.doFilter(ErrorFilter.java:42)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298)
at org.apache.jk.server.JkCoyoteHandler.invoke(JkCoyoteHandler.java:190)
at org.apache.jk.common.HandlerRequest.invoke(HandlerRequest.java:291)
at org.apache.jk.common.ChannelSocket.invoke(ChannelSocket.java:776)
at org.apache.jk.common.ChannelSocket.processConnection(ChannelSocket.java:705)
at org.apache.jk.common.ChannelSocket$SocketConnection.runIt(ChannelSocket.java:898)
at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:690)
at java.lang.Thread.run(Thread.java:662)

回答1:

This is not a Nullpointer exception.
This is an Illegal state exception.

This occurs when the session has been invalidated/expired, and you try to access it.

Session gets invalidated as follows.

session.invalidate();

After invalidate is called, you cant use the session.

Session expires when they timeout. After they expire, if you try to use it, it will throw the same exception.

These are the ways you can manually set a timeout.

set your timeout in web.xml. This is set in minutes.

<session-config>
   <session-timeout>30</session-timeout> 
</session-config>

Or you can set it in in your java as well.

public void setMaxInactiveInterval(int interval)

session.setMaxInactiveInterval(30*60); // This we set in seconds. 

Here we specify the time, in seconds, between client requests before the servlet container will invalidate this session. A negative time indicates the session should never timeout.

Make sure the operation you are doing is not taking longer than the timeout time. Else you will have to reset the value.

EDIT:
It is not possible to recover from it in a clean manner. The session will get invalidated/unusable, and you will need to create a new session and repopulate data. Generally people are redirected to an alternate Error PAge instead of showing the Stack Trace. "Your session has expired. Please login again."

Use request.isRequestedSessionIdValid() to identify whether the session ID is still valid.

HttpSession session =httpReg.getSession(false);
if( !request.isRequestedSessionIdValid() )
{
        //comes here when session is invalid.
        // redirect to a clean error page "Your session has expired. Please login again."
}

Another option is to use handle the IllegalExceptionState using try catch

HttpSession session =httpReg.getSession(false);
try
{
     if(session != null)
     { 
       Date date = new Date(session.getLastAccessedTime()); 
    }
}
catch( IllegalStateException ex )
{
      //comes here when session is invalid.
      // redirect to a clean error page "Your session has expired. Please login again."
}

Side Note: If you do have a process which is taking a long time to complete and sessions are timing out (ex: parsing really large data records ). You should consider taking them out of the web application, and use simple java to run them as a process.



回答2:

Your exception shows that you have invalidated the session, by calling .invalidate(), but are trying to use it. This is not possible.

Whenever you invalidate() a session, don't use it anymore.