2015-08-13 2 views
1

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

У нас есть веб-приложение 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»).

<action path="/login" 
     type="com.<...>.LoginAction" 
     name="loginForm" 
     scope="session" 
     validate="false"> 
     <forward name="success" path="/completeLogin" internal="true"/> 
     [...] 
    </action> 

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

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

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

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

<action path="/completeLogin" 
     type="com.<...>.CompleteLoginAction" 
     name="loginForm" 
     scope="session">    
     <forward name="success" path="home.jsp"/> 
     [...] 
    </action> 

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

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

Теперь, некоторые вещи, которые я пытался до приезда сюда:

  • У нас есть класс, реализующий интерфейс HttpSessionListener, который уведомляет нас, когда HttpSession создается или уничтожается.Во всех случаях, которые я тестировал, я всегда вижу уведомление о создании исходного и второго http-сеансов, но я никогда не получаю уведомление для сеанса уничтожение. Я предполагаю, что weblogic должен иметь исходную сессию где-то и никогда не уничтожать ее, а вместо этого создал новую.
  • Тем не менее я позаботился о том, чтобы проверить вызовы метода HttpSession # invalidate() и не вижу никаких вызовов в наших фильтрах, ActionServlet или классах Action per se в потоке, указанном выше.
  • Класс RequestDispatcher специфичен для контейнера, то есть реализация поставщика фактически вызывается во время выполнения при получении экземпляра диспетчера. Я предположил, что что-то может быть неправильным в диспетчере Oracle, так как никто из других поставщиков не имеет проблемы (и тот же код выполняется), поэтому я открыл запрос на обслуживание с Oracle и все еще общаюсь с некоторыми из их инженеров, чтобы найти решение, но У меня очень тяжелое время, доказывая им мою проблему, несмотря на бесчисленные файлы журналов, которые я отправил им, объясняя эту проблему.
  • Чтение некоторых документов Oracle, я понял, что, как и большинство сервлетов, объекты HttpSession тесно связаны с браузером Cookies. В нашей конфигурации мы не используем ни одну форму session persistence, мы также не создаем никаких дополнительных файлов cookie, а просто сохраняем атрибуты http session. Наш клиент также подтвердил, что файлы 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 { 
     [...] 
} 

Patch:

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> 

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

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

<BEA-000000> <[email protected] - /ourwebapp/login.do: SessionID not found for [email protected][app:ourwebapp module:ourwebapp path:/chapel spec-version:2.5]> 
<BEA-000000> <[email protected] - /ourwebapp/login.do: Creating new session> 

[...]

(неудача)

<BEA-000000> <[email protected] - /ourwebapp/getHomePage.do: [RemoteSessionFetching] obtained workManager: null> 
<BEA-000000> <[email protected] - /ourwebapp/getHomePage.do: Servername: localhost> 
<BEA-000000> <[email protected] - /ourwebapp/getHomePage.do: Serverport: 7001> 
[..] 
<BEA-000000> <[email protected] - /ourwebapp/getHomePage.do: SessionID not found for [email protected][app:ourwebapp module:ourwebapp path:/ourwebapp spec-version:2.5]> 
<BEA-000000> <[email protected] - /ourwebapp/getHomePage.do: Creating new session> 

Так что я думаю, мой вопрос, кто-нибудь когда-либо сталкивались с этим вопросом до того, в нижней строке мой HTTP сессии не то же самое после RequestDispatcher # вперед() при запуске на 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)); 
     } 
    } 
+0

Обновление по этому вопросу, если у кого-то возникнет такая же проблема. Казалось бы, проблема в том, что проблема на самом деле выше в моем случае. Другое приложение, размещенное на отдельном экземпляре weblogic, отправляет свой собственный файл cookie JSESSIONID в первоначальный запрос на вход, и я считаю, что это то, что путает weblogic. Пытаясь подтвердить это, обновите вопрос еще раз. Также изначально предлагаемая работа не может работать. – schwarz

ответ

0

Я устранил эту проблему сам, не легкий, но оказывается, были вовлечены несколько факторов. Прежде всего, в коде есть место, где сеанс будет бесполезно аннулирован, я удалил это. Но во-вторых, и самое интересное, наше приложение было доступно нашим клиентом из другого приложения на другом экземпляре WLS, но с использованием того же имени домена. I.E .: www.abc.com/customer_app, перенаправленный на www.abc.com/our_web_app, я узнал, что при этом браузер включает все файлы cookie из/customer_app в запрос перенаправления. Среди них был также файл cookie JSESSIONID (который не существует в контексте/our_web_app). Это была проблема.

WLS отлично реагирует на первый раз, когда видит неизвестный JSESSIONID-файл cookie, он просто игнорирует его (поскольку он не может отображать его в памяти на любой сеанс http) и создает новый для нашего_web_app. Проблема заключается в том, что оба файла cookie были установлены на cookie-path '/', что означает, что всякий раз, когда в нашем приложении происходит перемотка, WLS иногда читает старый бессмысленный cookie JSESSIONID, иногда соответствующий новый cookie, созданный для нашего_web_app. Когда он прочитает старый файл cookie, он снова - не узнает его и создаст новый сеанс http (который даст новый JSESSIONID-файл cookie), тем самым потеряв любую информацию из ранее созданного сеанса http (после входа в систему).

Хорошим временным обходным путем было установить более конкретный путь к файлам cookie для файлов cookie, созданных с помощью нашего приложения, таким образом они кажутся первыми в списке файлов cookie и всегда считаются первыми перед любыми другими кукисами JSESSIONID.

I.E. Раньше, когда на печенья пути '/' список печенья, возможно, появился как: SOME_CUSTOMER_COOKIE1: значению1, SOME_CUSTOMER_COOKIE2: значение2, JSESSIONID: oldID, JSessionID: newCorrectID

После установки куки-путь '/ our_web_app' для печенья, созданного в нашем приложении: JSessionID: newCorrectID, SOME_CUSTOMER_COOKIE1: value1, SOME_CUSTOMER_COOKIE2: значение2, JSESSIONID: oldID

в идеале, это уже было бы предотвратить, либо убедившись, что не использовать один и тот же домен НАНЕ для обоих приложений или даже изменения свойство cookie-name для нашего_web_app (например, JSESSIOND -> WEB_APP_SESSION_ID), но по техническим причинам (в основном на стороне клиента, связанные с балансировкой нагрузки и проблемами затрат), ни один из вариантов не был нас.

Надеюсь, что это поможет кому-то в один прекрасный день.

+0

Также временный патч удален, возможно, не работал по другим причинам. – schwarz

 Смежные вопросы

  • Нет связанных вопросов^_^