我在这里提出了很长的问题并且稍微没有选项,所以我想我会转而参考这个网站,它似乎总能解决我的大部分问题。对于长篇文章感到抱歉,但有些背景很重要。
我们有一个java Web应用程序(.war),它可以托管在多个应用程序服务器上(Tomcat用于内部开发,Weblogic 10.3.5用于某些客户,Websphere用于其他客户,Glassfish用于其他客户)。对于它的价值,它是关于jdk 1.6
我们使用旧版本的struts(1.0.2)进行动作映射,在我们的web.xml文件中定义了几个过滤器,我们还为一些应用程序服务器提供了其他配置文件(如weblogic.xml)用于weblogic的文件,其中包含很少的元素)。视图层都是带有一些js的jsp。
我们有一个主入口点/类来处理扩展Struts ActionServlet类的http请求。
在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(),这在第一个过滤器中是预期的。)< / p>
在第一个操作成功结果之后,我们将内部请求如上所示转发到下一个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并循环查看如果我找到任何名称为&#34; JSESSIONID&#34;并检查他们的价值。如果它们的值与当前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>
所以我猜我的问题是,有没有人曾经遇到过这个问题,底线是我的http会话在weblogic 10.3.5上运行后的RequestDispatcher#forward()之后是不一样的?或许同时有任何临时解决方案的想法?
我可能忘记了什么?
我的第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));
}
}
答案 0 :(得分:0)
我自己解决了这个问题,不是一件容易的事,但事实证明,涉及到几个因素。首先,在代码中仍然存在一个地方,会话将被不必要地无效,我删除了它。 但其次,最有趣的是,我们的客户从不同WLS实例上的另一个应用程序访问我们的应用程序,但使用相同的域名。 I.E。: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路径'/'上,这意味着每当我们的应用程序中发生转发时,WLS有时会读取旧的无意义的JSESSIONID cookie,有时会为our_web_app创建正确的新cookie。当它读取旧cookie时,它会 - 再次 - 不识别它并创建一个新的http会话(产生一个新的JSESSIONID cookie),从而丢失先前创建的http会话中的任何信息(登录后)。
一个好的临时解决方法是在通过我们的应用程序创建的cookie上设置更具体的cookie路径,这样,它们似乎首先出现在cookie列表中,并且在任何其他JSESSIONID cookie之前始终被认为是第一个。
即。在cookie-path'/'之前,cookie列表可能显示为: SOME_CUSTOMER_COOKIE1:value1,SOME_CUSTOMER_COOKIE2:value2,JSESSIONID:oldID,JSESSIONID:newCorrectID
为我们的网络应用中创建的Cookie设置cookie-path'/ our_web_app'后: JSESSIONID:newCorrectID,SOME_CUSTOMER_COOKIE1:value1,SOME_CUSTOMER_COOKIE2:value2,JSESSIONID:oldID
理想情况下,这可以通过确保不为两个应用程序使用相同的域nane甚至更改my_web_app的cookie-name属性(例如JSESSIOND - &gt; WEB_APP_SESSION_ID)来防止,但出于技术原因(主要是在客户方面,与负载平衡和成本问题相关)对我们来说都不是一种选择。
希望有一天能帮到某人。