Java Servlet HttpSession не поддерживается в сеансе Weblogic впередJAVA

Программисты JAVA общаются здесь
Ответить
Anonymous
 Java Servlet HttpSession не поддерживается в сеансе Weblogic вперед

Сообщение Anonymous »

Я проделал долгий путь, задавая этот вопрос здесь, и у меня немного не осталось выбора, поэтому я решил вместо этого обратиться к этому сайту, который, кажется, всегда имеет ответ на большинство моих проблем. Извините за длинный пост, но некоторый контекст важен.

У нас есть веб-приложение Java (.war), которое можно разместить на нескольких серверах приложений (Tomcat для собственной разработки, Weblogic 10.3.5 для некоторых клиентов, Websphere для других клиентов и Glassfish для других). Что бы это ни стоило, это jdk 1.6.

Мы используем старую версию struts (1.0.2) для сопоставления действий, в нашем файле web.xml определено несколько фильтров, у нас также есть дополнительные файлы конфигурации для некоторых серверов приложений (например, файл weblogic.xml для weblogic с небольшим количеством элементов). Уровень представления — это весь JSP с некоторыми JS.

У нас есть основная точка входа/класс для обработки http-запросов, который расширяет класс Struts ActionServlet.

Вот моя проблема при развертывании и тестировании приложения на сервере weblogic (WLS) 10.3.5, проблема, которую я собираюсь описать, никогда не встречалась ни на одном из других серверов приложений.

Пользователи попробуют выполнить простое начальное действие регистрации, вызвав начальное действие struts (например, «/login»).



[...]



Фильтры применяются, https-сессия инициируется (выполняется проверка request.getSession(false), а затем вызывается request.getSession(), если HttpSession оказывается нулевым, что ожидается в первых фильтрах).

После успешного результата этого первого действия мы затем перенаправляем внутренний запрос, как показано выше, на следующее действие Struts. Это действие также завершается успешно и перенаправляет запрос на следующее действие Struts.

Прежде чем двигаться дальше, важно отметить, что оба этих действия устанавливают важные атрибуты в объекте HttpSession, которые позже используются в бизнес-логике нашего приложения.

Следующее действие отображается на странице .jsp (которая преобразуется в невнутреннее действие ActionForward):



[...]



Непосредственно перед завершением действий /login и /completeLogin я печатаю идентификатор HttpSession, чтобы убедиться, что один и тот же идентификатор сеанса повторно используется от одного вызова к другому.

Проблема заключается в том, что когда мой ActionServlet отправляет третий запрос через метод RequestDispatcher#forward(ServletRequest,ServletResponse), третье действие завершается неудачей, потому что мы ожидаем, что это произойдет. получить некоторые атрибуты из HttpSession (которые ранее были успешно установлены), но их нет, потому что, к удивлению, был сгенерирован новый HttpSession и передан этому третьему действию вместо HttpSession исходного запроса. (Я печатаю идентификатор и вижу, что он отличается от двух предыдущих напечатанных идентификаторов), поскольку мне не удается получить доступ к этим атрибутам, приложение выдает исключение, и пользователь не может использовать приложение, потому что он/она просто не может войти в систему.

Теперь некоторые вещи, которые я пробовал, прежде чем прийти сюда:
  • У нас есть класс, реализующий интерфейс HttpSessionListener, который уведомляет нас, когда HttpSession создается или уничтожается. Во всех протестированных мной случаях я всегда вижу уведомление о создании исходного и второго http-сеанса, но никогда не получаю уведомления о уничтожении сеанса. Я предполагаю, что у weblogic где-то должен быть исходный сеанс, и он никогда не уничтожал его, а вместо этого создавал новый.
  • Тем не менее, я проверил вызовы метода HttpSession#invalidate() и не вижу никаких вызовов в наших классах Filters, ActionServlet или Action как таковых в потоке, указанном выше.
  • Класс RequestDispatcher зависит от контейнера, т. е. реализация поставщика фактически вызывается в время выполнения при получении экземпляра диспетчера. Я предположил, что что-то не так в диспетчере Oracle, поскольку ни у одного из других поставщиков нет проблемы (и выполняется тот же код), поэтому я открыл запрос на обслуживание в Oracle и все еще общаюсь с некоторыми из их инженеров, чтобы найти решение, но мне очень сложно доказать им мою проблему, несмотря на бесчисленные файлы журналов, которые я отправил им с объяснением проблемы.
  • Прочитав некоторую документацию Oracle, я понял, что, как и большинство сервлетов, объекты HttpSession тесно связаны с файлами cookie браузера. В нашей конфигурации мы не используем какую-либо форму сохранения сеанса, мы также не создаем никаких дополнительных файлов cookie, а просто сохраняем атрибуты сеанса http. Наш клиент также подтвердил, что в его браузерах включены файлы cookie. Мне также удалось воспроизвести проблему в двух браузерах внутри страны. Затем я начал исследовать файлы cookie, и на данный момент это, кажется, моя основная идея. Я проверил, присутствовали ли какие-либо файлы cookie после первоначальных фильтров. К моему удивлению, я ожидал отсутствия файлов cookie, поскольку, насколько я понимаю, срок действия файла cookie по умолчанию, созданного для сеанса, истекает после завершения сеанса (закрытие браузера/выход из приложения).
Я пошел дальше и попробовал следующее, и, похоже, какое-то время это работало, но теперь пользователь вернулся к нам и заявил, что пользователи все еще время от времени выходят из системы. Что еще хуже, эта проблема непостоянна, иногда она возникает, иногда нет. Грязный патч, который я написал, был в начальном LoginAction. Я сканирую файлы cookie в объекте запроса и проверяю, найду ли я файлы cookie с именем «JSESSIONID», и проверяю их значение. Если их значение не совпадает со значением идентификатора текущего сеанса HTTP, я обновляю файл 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 выглядит следующим образом:




false

org.apache.commons.lang.*




Я также включил журналы HttpDebug на самой консоли администратора weblogic и часто вижу это сообщение, когда пересылка запроса вот-вот завершится неудачно:

(Создание начального сеанса)





[...]

(неудача)




[..]




Итак, я думаю, мой вопрос: сталкивался ли кто-нибудь с этой проблемой раньше? Суть в том, что мой http-сеанс не тот же после RequestDispatcher#forward() при работе в weblogic 10.3.5? Или, возможно, есть какие-нибудь идеи для временного обходного пути?

Что-нибудь, что я, возможно, забыл?

Мое третье действие вызывает 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));
}
}
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «JAVA»