3

我們在IIS7.5後面使用Tomcat 6.29,使用spring,hibernate和struts2框架。我們現在開始注意到,服務器會話在Ajax請求中發生混亂。在tomcat上混淆了用戶會話

更多有關該問題的

  • 用戶1名的請求第1頁,用戶2請求第2頁的信息。但是user1獲得服務page2,而user2獲得服務器page1。
  • 會話id也在變化,但在刷新頁面時,會提供正確的頁面。
  • 當用戶數量很高時,問題似乎更常發生。

任何指向問題根源的指針都會有幫助,代碼運行良好,用戶數量較少,並且不會報告此類實例。

編輯

的web.xml

<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> 

<display-name>bm</display-name> 
<context-param> 
<param-name>contextConfigLocation</param-name> 
<param-value>classpath:spring/*Context.xml</param-value> 
</context-param> 
<filter> 
<filter-name>encodingFilter</filter-name> 
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> 
<init-param> 
    <param-name>encoding</param-name> 
    <param-value>UTF-8</param-value> 
</init-param> 
<init-param> 
    <param-name>forceEncoding</param-name> 
    <param-value>true</param-value> 
</init-param> 
</filter> 
<filter> 
<filter-name>struts2</filter-name> 
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class> 
</filter> 
<filter-mapping> 
<filter-name>encodingFilter</filter-name> 
<url-pattern>/*</url-pattern> 
</filter-mapping> 
<filter-mapping> 
<filter-name>struts2</filter-name> 
<url-pattern>/*</url-pattern> 
</filter-mapping> 
<listener> 
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> 
</listener> 
<listener> 
    <listener-class>org.apache.struts2.tiles.StrutsTilesListener</listener-class> 
</listener> 

struts.xml的

<result-types> 
     <result-type name="jasper" class="org.apache.struts2.views.jasperreports.JasperReportsResult"/> 
     <result-type name="tiles" class="org.apache.struts2.views.tiles.TilesResult" /> 
    </result-types> 

    <interceptors> 

     <interceptor name="sessionLoggin" class="com.inrev.bm.interceptor.IRLoggingInterceptor" /> 
     <interceptor name="appAccess" class="appAccessInterceptor" /> 

     <interceptor-stack name="newStack"> 
      <interceptor-ref name="exception"/> 
      <interceptor-ref name="alias"/> 
      <interceptor-ref name="servletConfig"/> 
      <interceptor-ref name="i18n"/> 
      <interceptor-ref name="prepare"/> 
      <interceptor-ref name="chain"/> 
      <interceptor-ref name="debugging"/> 
      <interceptor-ref name="scopedModelDriven"/> 
      <interceptor-ref name="modelDriven"/> 
      <interceptor-ref name="fileUpload"/> 
      <interceptor-ref name="checkbox"/> 
      <interceptor-ref name="multiselect"/> 
      <interceptor-ref name="staticParams"/> 
      <interceptor-ref name="params"> 
       <param name="excludeParams"> dojo\..*,^struts\..*</param> 
      </interceptor-ref> 
      <interceptor-ref name="actionMappingParams"/> 
      <interceptor-ref name="sessionLoggin"/> 
      <interceptor-ref name="appAccess"/> 
     </interceptor-stack> 
    </interceptors> 

<default-interceptor-ref name="newStack"/> 

其他信息

1)用戶通過提交一個表單,上我們執行以下登錄登錄在,

public class xxxAction extends ActionSupport implements SessionAware 
{ 
    public String execute() 
{ 
     session.clear(); 
     if (session instanceof org.apache.struts2.dispatcher.SessionMap) 
     { 
    try 
    { 
     ((org.apache.struts2.dispatcher.SessionMap) session).invalidate(); 
    } 
    catch (IllegalStateException e) { 
     log.error("Session Invalidate Failed ", e); 
     } 

     //Authorization code happens here 
     session.put("orgs", orgs); 
    session.put("currentOrg", org); 
    session.put("permission", adminDAO.getRolePermission(orgs.get(0).getRoleId())); 
    session.put("simplyApp", simplyApp); 
    session.put("user", user); 

     return "login" 
    } 
} 

正在使用2)O的是2008年窗口RC2

EDIT2操縱器CODE

INTERCEPTOR 1

public String intercept(ActionInvocation invocation) throws Exception 
{ 
    String result = null; 

    String className = invocation.getAction().getClass().getName(); 
    Map session = invocation.getInvocationContext().getSession(); 

    IRUser user = (IRUser) session.get("user"); 
    IROrgname org = (IROrgname)session.get("currentOrg"); 
    IRAppDetails simplyApp = (IRAppDetails)session.get("simplyApp"); 
    String sessionId = (String)session.get("sessionId"); 
    boolean switchUser =session.get("switchUser")!=null ? (Boolean)session.get("switchUser") : false; 

    if(className.indexOf("IRLoginAction")!=-1 || className.indexOf("IRContactUsAction")!=-1 
      || className.indexOf("IRIPNAction")!=-1 || className.indexOf("IRPaymentAction")!=-1 
      || className.indexOf("IRServiceAction")!=-1 || className.indexOf("IRAppBossAction") !=-1) 
    { 
     result= invocation.invoke(); 
     session.put("PREV_CLASS_NAME", className); 
    } 
    else if(!(className.indexOf("IRLoginAction")!=-1) && (user !=null && org!=null)) 
    { 
     if(!IRSessionManager.getInstance().compareSession(user.getUserId(), sessionId) && !switchUser) 
     { 
      session.clear(); 
      if (session instanceof org.apache.struts2.dispatcher.SessionMap) 
      { 
       try 
       { 
        ((org.apache.struts2.dispatcher.SessionMap) session).invalidate(); 
       } 
       catch (IllegalStateException e) 
       { 
        log.error("Session Invalidate Failed ", e); 
       } 
      } 
      result = "sessionDuplicated"; 

     } 
     else 
     { 
      result= invocation.invoke(); 
      session.put("PREV_CLASS_NAME", className); 
     } 
    } 
    else if(className.indexOf("widgets") !=-1) 
    { 
     result= invocation.invoke(); 
    } 
    else if(className.indexOf("ActionSupport") !=-1) 
    { 
     result= invocation.invoke(); 
    } 
    else if (!(className.indexOf("IRLoginAction")!=-1) && (user ==null || org==null || simplyApp==null)) 
    { 
     result = "sessionExpired"; 
    } 

    return result; 
} 

INTERCEPTOR 2

​​
+0

我們需要知道更多有關配置。攔截器堆棧是什麼樣的?你如何執行身份驗證?你的web.xml的樣子是什麼(其他過濾器/ servlet是什麼)? – Quaternion

回答

7

我已經調試上的遺留項目(不是我的)類似前兩天的東西。

原來這是定製的攔截器的錯。

檢查自定義攔截器,我可以在你的堆棧看到,

 <interceptor-ref name="sessionLoggin"/> 
     <interceptor-ref name="appAccess"/> 

,並確保他們的代碼是Thread Safe(避免攔截,而不是同步領域你所有的東西,只用局部變量)。

例如,考慮中的代碼:

public abstract class ThreadUnsafeInterceptor extends AbstractInterceptor { 

    private Map<String, Object> session; // <!-- Thread Unsafe 

    public final String intercept(ActionInvocation invocation) throws Exception { 
     session = invocation.getInvocationContext().getSession();  
     /* Do stuff */ 

     System.out.println(session.get("myObject"));   

     return invocation.invoke(); 
    } 
} 

這樣,當用戶1進入的方法,它設置共享session對象與其會話; 如果User2在User1尚未完成時輸入方法,則User2將立即用其會話覆蓋session對象,並且User1將引用User2會話而不是自己的會話。

爲了讓線程安全應該像如下:

public abstract class ThreadSafeInterceptor extends AbstractInterceptor { 

    public final String intercept(ActionInvocation invocation) throws Exception { 

     Map<String, Object> session; // <!-- Thread Safe 

     session = invocation.getInvocationContext().getSession(); 

     /* Do stuff */ 

     System.out.println(session.get("myObject"));   

     return invocation.invoke(); 
    } 
} 

編輯:

你的攔截器存在一些問題:

1)請求不能被訪問如此(如所述here):

HttpServletRequest request = ServletActionContext.getRequest(); 

從一個Struts2的攔截器中訪問請求的正確方法是:

// Constants are from StrutsStatics interface 
HttpServletRequest request = (HttpServletRequest) context.get(HTTP_REQUEST); 

2)如果您不希望立即返回invocation.invoke();,請注意,將其賦值給result字符串將觸發「流」,和invoke()後的線路將操作執行後執行,as described here

public String intercept(ActionInvocation invocation) throws Exception { 

    String className = invocation.getAction().getClass().getName(); 
    long startTime = System.currentTimeMillis(); 
    System.out.println("Before calling action: " + className); 

    String result = invocation.invoke(); 

    long endTime = System.currentTimeMillis(); 
    System.out.println("After calling action: " + className 
      + " Time taken: " + (endTime - startTime) + " ms"); 

    return result; 
}