java web用户频繁非正常登出系统(session丢失)的原因分析及解决思路

   项目开发完成以后,部署电信服务器中测试时,发现登录的用户不时会出现自动登出回登录页的情况,而且出现的频率不等。分析原因如下。

      首先考虑session失效,我在工程中设置session失效的时间间隔为30分钟,而出现这种情况的时间间隔普遍较小,有时甚至刚刚登录立马登出系统,所以可以排除此原因。在项目中,我创建了拦截器SessionInterceptor,对于用户动作实施拦截。对于三种情况的动作,拦截并返回登录页面:1.用户未登录 2.用户登录在线超时 3.session中记录的用户id和动作传递的用户id不同(非本人操作),代码如下:

[java]  view plain copy
  1. public class SessionInterceptor extends AbstractInterceptor {  
  2.       
  3.     private static Logger log = Logger.getLogger(SessionInterceptor.class);  
  4.       
  5.     @Override  
  6.     public String intercept(ActionInvocation invocation) throws Exception   
  7.     {  
  8.         ActionContext ctx=ActionContext.getContext();  
  9.         Map session=ctx.getSession();  
  10.         HttpServletRequest request=(HttpServletRequest)ctx.get(ServletActionContext.HTTP_REQUEST);  
  11.         HttpSession hsession=request.getSession(false);  
  12.         String sessionId=hsession.getId();  
  13.         Action action=(Action)invocation.getAction();  
  14.         //Long userlogicId=Long.parseLong(invocation.getInvocationContext().getParameters().get("userlogicId").toString());  
  15.         //Date logintime=(Date)session.get(WebConstant.LOGIN_TIME);  
  16.         Date logintime=(Date)hsession.getAttribute(WebConstant.LOGIN_TIME);  
  17.           
  18.         if((String)session.get(WebConstant.USER_ID)==null){    //登录超时  
  19.             log.debug(" 未登录或登录超时:"+sessionId);   
  20.             hsession.invalidate();  
  21.             return Action.LOGIN;  
  22.         }  
  23.           
  24.         else if(logintime==null)                               //未登录  
  25.         {  
  26.              log.debug("未登录:"+sessionId);  
  27.              hsession.invalidate();  
  28.              return Action.LOGIN;  
  29.         }  
  30.           
  31.         else{   
  32.              try{  
  33.                  String[] userlogicIds=((String[])invocation.getInvocationContext().getParameters().get("userlogicId"));  
  34.                  String userlogicIdstr=userlogicIds[0];  
  35.                  Long userlogicId=Long.parseLong(userlogicIdstr);                  
  36.                  if(userlogicId!=Long.parseLong(session.get(WebConstant.USER_LOGICID).toString())) { //请求用户和登录用户不同  
  37.                    {          
  38.                        log.debug("操作用户id"+userlogicId.toString()+"与会话用户id"+session.get(WebConstant.USER_LOGICID).toString()+"不一致");  
  39.                       // hsession.invalidate();  
  40.                        return Action.LOGIN;  
  41.                    }  
  42.                  }  
  43.               }  
  44.               catch (NullPointerException e) {  
  45.                   hsession.invalidate();  
  46.                   return  Action.LOGIN;  
  47.                 }  
  48.           
  49.         }  
  50.            
  51.             return invocation.invoke();  
  52.            
  53.     }  
  54.   
  55. }  


  通过查看日志发现,被拦截时session中的内容为空,故被拦截跳转回登录页面。但是在这之间,并无程序如session.invalidate()让session失效的操作,且session并没有超时,故基本可判定是session丢失的情况。

     上网查看了tomcat下session丢失的原因,有以下几种:1.跨域访问。2.使用多台tomcat服务器进行负载均衡,未进行session复制操作导致session丢失。3.未对session进行持久化操作。逐一分析如下:

    1.跨域访问。所谓跨域访问,即如果在A网站中,我们希望用Ajax来获得B网站中的特定内容,如果A网站与B网站不在同一个域当中,则会出现跨域访问的情况。对于多个子系统的项目而言,多次通过浏览器进行跨域访问,会引起session不一致和session丢失的情况。解决跨域而导致的session丢失的情况处理参考《跨域,跨服务器调用的时候session丢失的问题总结》。由于本项目未采用跨域访问,故排除这种可能性。

     2.使用多台tomcat服务器实现负载均衡导致的session丢失。当使用tomcat服务器进行负载均衡时,如果不对session共享,会出现session唯一的情况,同样会导致session丢失。这就需要各服务器做到session同步,也就是所谓的session复制。Session复制,指的是集群环境下,多台应用服务器之间同步session,确保session保持一致,同时保持session中的内容一致,对外透明,就像一台应用服务器一样。对于这种情况的避免session丢失的处理参考《Apache+Tomcat负载均衡 session复制》。在项目当中,并未使用多台tomcat服务器实现负载均衡,故同样可以排除这种情况导致的session丢失。

     3.session未做持久化操作导致丢失在客户端每个用户的Session对象存在Servlet容器中,如果Tomcat服务器重起/当机的话该session就会丢失,而客户端的操作应为session的丢失而造成数据丢失,而且当前用户访问量巨大,每个用户的Session里存放大量的数据的话,那么就很占用服务器大量的内存,从而是服务器的性能受到影响。因此,需要对session进行持久化操作。持久化操作的方法参见文章《tomcat session持久化》。在本项目中,session丢失的情况是出现在项目运行的过程中,而不是tomcat重启的时候,因此,可以排除是由于没有做持久化操作而导致的session丢失。

      经过上述分析,排除了可能导致session丢失的几种主要情况。这再一次让我感觉无计可施。而项目验收时频繁出现用户登出系统的情况又让这个问题的解决迫在眉睫。正当一筹莫展的时候,从一次偶尔的交谈中得知,服务器在搭建的过程中,并非直接使用tomcat,而是使用了apache作为代理服务器,转发请求至后台的tomcat服务器,会不会是由于代理的原因导致的呢?通过查阅资料发现,tomcat中的应用contex路径为 /portal,而外部访问context路径为 /,JSESSIONID的值从浏览器经过反向代理到达tomcat时,由于cookie内外路径不一致,导致tomcat每次重写设置JSESSIONID的值,导致session丢失的现象。在apache的000-default.conf中需要通过ProxyPassReverseCookiePath指令做一个路径映射,如下图:



java web用户频繁非正常登出系统(session丢失)的原因分析及解决思路_第1张图片


在完成上述配置后,重启tomcat和apache,果然再没有出现过session丢失的情况。


你可能感兴趣的:(java/ssh)