[英]Java Servlet HttpSession not maintained on Weblogic session forward
我在這里提出這個問題已經走了很長一段路,並且略有超出選擇范圍,因此我想我應該轉而引用此站點,該站點似乎總是可以解決我的大多數問題。 很抱歉,很長的帖子,但某些情況很重要。
我們有一個Java Web應用程序(.war),它可以托管在多個應用程序服務器上(內部開發為Tomcat,某些客戶為Weblogic 10.3.5,其他客戶為Websphere,其他客戶也為Glassfish)。 對於它的價值,它在jdk 1.6上
我們使用舊版本的Struts(1.0.2)進行操作映射,在我們的web.xml文件中定義了幾個過濾器,還為某些應用程序服務器提供了其他配置文件(例如,用於weblogic的weblogic.xml文件)元素很少)。 視圖層都是帶有一些js的jsp。
我們有一個主要的入口點/類來處理http請求,它擴展了Struts ActionServlet類。
這是在weblogic(WLS)服務器10.3.5上部署和測試應用程序時的問題,我要描述的問題在任何其他應用程序服務器上都從未遇到過。
用戶將通過調用初始的struts動作(例如“ / login”)來嘗試簡單的初始記錄動作。
<action path="/login"
type="com.<...>.LoginAction"
name="loginForm"
scope="session"
validate="false">
<forward name="success" path="/completeLogin" internal="true"/>
[...]
</action>
應用過濾器,啟動httpsession(檢查request.getSession(false),然后如果HttpSession看起來為null,則調用request.getSession(),這在第一個過濾器中是期望的)。
在成功執行第一個操作之后,我們將內部請求如上所示轉發到下一個Struts操作。 該操作也成功完成,並將請求轉發到下一個struts操作。
在繼續之前,重要的是要注意,這兩個操作都在HttpSession對象中設置了重要的屬性,這些屬性隨后將在我們的應用程序業務邏輯中使用。
下一個動作映射到.jsp頁(轉換為非內部ActionForward):
<action path="/completeLogin"
type="com.<...>.CompleteLoginAction"
name="loginForm"
scope="session">
<forward name="success" path="home.jsp"/>
[...]
</action>
在/ login和/ completeLogin操作都完成之前,我將打印HttpSession id,以確保從一個調用到另一個調用可重復使用相同的會話id。
問題是當我的ActionServlet通過RequestDispatcher#forward(ServletRequest,ServletResponse)方法調度第三個請求時,第三個操作失敗,因為我們希望從HttpSession中檢索某些屬性(先前已成功設置),但沒有出現,因為令人驚訝的是,生成了一個新的HttpSession並將其傳遞給第三個操作,而不是原始請求的HttpSession。 (我打印了ID,發現它與之前的2個ID有所不同),因為我無法訪問這些屬性,因此應用程序將引發異常,並且用戶無法使用該應用程序,因為他/她根本無法登錄。
現在,在來到這里之前我已經嘗試了一些方法:
因此,我繼續嘗試以下方法,它似乎已經起作用了一段時間,但是現在用戶回到我們身邊,指出用戶仍然不時退出。 更糟的是,這個問題並不一致,有時會發生,有時並沒有。 我寫的骯臟補丁是在最初的LoginAction上。 我在請求對象中掃描cookie,然后循環查看是否找到任何名稱為“ JSESSIONID”的cookie並檢查其值。 如果它們的值與當前http會話的會話ID的值不匹配,那么我將更新cookie。 它工作了一段時間,但問題似乎現在又回來了。
該補丁的代碼示例:
public class LoginAction extends GenericAction {
private static final Logger log = LoggerFactory.getLogger(LoginAction.class);
private static final String JSESSIONID_COOKIE_NAME = "JSESSIONID";
@Override
public ActionForward internalPerform(ActionMapping mapping, BaseForm form,
HttpServletRequest request, HttpServletResponse response) throws InvalidSessionException {
String clientOwner = null;
String registeredHost = null;
/*
* Temporary patch for Weblogic JAS. Will be removed eventually.
*/
verifyJSessionIdCookies(request, response);
try {
[...]
}
補丁方式:
protected void verifyJSessionIdCookies(HttpServletRequest request, HttpServletResponse response) {
Cookie[] existingCookies = request.getCookies();
HttpSession session = request.getSession(false);
if (null != existingCookies && null != session) {
for (Cookie cookie : existingCookies) {
if (cookie.getName().equals(JSESSIONID_COOKIE_NAME) && !cookie.getValue().equals(session.getId())) {
log.debug("Updating current client JSESSIONID cookie from {} to value {}", cookie.getValue(),
session.getId());
cookie.setValue(session.getId());
}
}
}
}
}
我們的weblogic.xml文件如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<weblogic-web-app>
<container-descriptor>
<prefer-web-inf-classes>false</prefer-web-inf-classes>
<prefer-application-packages>
<package-name>org.apache.commons.lang.*</package-name>
</prefer-application-packages>
</container-descriptor>
我還已在weblogic管理控制台本身上啟用了HttpDebug日志,並且在轉發請求即將失敗時,經常會看到此消息:
(初始會話創建)
<BEA-000000> <HttpRequest@17756711 - /ourwebapp/login.do: SessionID not found for WASC=ServletContext@2256126[app:ourwebapp module:ourwebapp path:/chapel spec-version:2.5]>
<BEA-000000> <HttpRequest@17756711 - /ourwebapp/login.do: Creating new session>
[...]
(失敗)
<BEA-000000> <HttpRequest@11453786 - /ourwebapp/getHomePage.do: [RemoteSessionFetching] obtained workManager: null>
<BEA-000000> <HttpRequest@11453786 - /ourwebapp/getHomePage.do: Servername: localhost>
<BEA-000000> <HttpRequest@11453786 - /ourwebapp/getHomePage.do: Serverport: 7001>
[..]
<BEA-000000> <HttpRequest@11453786 - /ourwebapp/getHomePage.do: SessionID not found for WASC=ServletContext@2256126[app:ourwebapp module:ourwebapp path:/ourwebapp spec-version:2.5]>
<BEA-000000> <HttpRequest@11453786 - /ourwebapp/getHomePage.do: Creating new session>
所以我想我的問題是,以前有沒有人遇到過這個問題,最重要的是在weblogic 10.3.5上運行RequestDispatcher#forward()之后,我的http會話不一樣嗎? 或與此同時,關於臨時解決方案的任何想法?
我可能忘記了什么?
我的第3個動作調用request.getSession(),而不是request.getSession(false),因為假定此時已經創建了它,但是檢索它的屬性將顯示一個空的地圖/列表。
Weblogic中有什么不同之處可能導致此行為?
ActionServlet示例:
RequestDispatcher rd = getServletContext().getRequestDispatcher(path);
if (null == rd) {
String errorMessage = internal.getMessage(REQUEST_DISPATCHER, path);
log.debug(errorMessage);
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, errorMessage);
return;
}
if (null != request.getAttribute(Constants.INCLUDED_REQUEST)) {
rd.include(request, response);
} else {
try {
//fails after this call
rd.forward(request, response); [..]
第三動作:
public ActionForward perform(ActionMapping mapping, ActionForm form, HttpServletRequest request,
HttpServletResponse response) throws IOException, ServletException {
//displays a new id
log.debug("Http session after forward : {}", request.getSession(false).getId());
String mappingPath = mapping.getPath();
boolean outOfSessionAction = outOfSessionPaths.contains(mappingPath);
Attribute attr = null;
if (!outOfSessionAction) {
attr = request.getSession().getAttribute("attr1");
if (attr == null) {
//we should be retrieving this attribute but we fail because
//new HttpSession in the request object
return processException(request, mapping, new BusinessException(true));
}
}
我本人已經解決了這個問題,這不是一件容易的事,但是事實證明,涉及到幾個因素。 首先,代碼中仍有一個地方會不必要地使會話無效,我刪除了那個地方。 但是,第二點也是最有趣的是,我們的應用程序是由客戶從另一個WLS實例上但使用相同域名的另一個應用程序訪問的。 IE:www.abc.com/customer_app重定向到www.abc.com/our_web_app,據我了解,這樣做會使瀏覽器也將來自/ customer_app的所有cookie都包含在重定向請求中。 其中還有一個JSESSIONID cookie(在/ our_web_app的上下文中不存在)。 那個問題就在那里。
WLS第一次看到未知的JSESSIONID cookie時反應良好,它只是忽略了它(因為它無法將其映射到內存中的任何http會話中)並為our_web_app創建了一個新的cookie。 問題在於兩個cookie都設置在cookie路徑“ /”上,這意味着只要在我們的應用程序中發生轉發,WLS有時就會讀取舊的無意義的JSESSIONID cookie,有時還會為our_web_app創建正確的新cookie。 當它讀取舊的cookie時,它將再次-無法識別它並創建一個新的http會話(產生一個新的JSESSIONID cookie),從而丟失了先前創建的http會話中的任何信息(登錄后)。
一個不錯的臨時解決方法是在通過我們的應用程序創建的cookie上設置一個更特定的cookie路徑,這樣,它們似乎首先出現在cookie列表中,並且始終被優先考慮在其他JSESSIONID cookie之前。
IE之前,在cookie路徑“ /”上時,cookie的列表可能顯示為:SOME_CUSTOMER_COOKIE1:value1,SOME_CUSTOMER_COOKIE2:value2,JSESSIONID:oldID,JSESSIONID:newCorrectID
為在我們的Web應用程序中創建的cookie設置cookie路徑“ / our_web_app”后:JSESSIONID:newCorrectID,SOME_CUSTOMER_COOKIE1:value1,SOME_CUSTOMER_COOKIE2:value2,JSESSIONID:oldID
理想情況下,可以通過確保不為兩個應用程序使用相同的域名nane或甚至更改our_web_app的cookie-name屬性(例如,JSESSIOND-> WEB_APP_SESSION_ID)來避免這種情況,但是出於技術原因(主要在客戶端) ,與負載平衡和成本問題有關)都不是我們的選擇。
希望這對某人有幫助。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.