Содержание

понедельник, 4 апреля 2011 г.

Как настроить приложение, чтобы избежать кэширования интернет-прокси и не попасть впросак

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

У меня был rich-client, который внутри использовал библиотеку NetX для загрузки и
открытия нового приложения по JNLP, короче вебстарт на коленке. Проблема
возникла у одного-двух клиентов после обновления версии на сервере.
NetX кэширует JNLP, но всегда обновляет её основываясь на Last-Modified
поле HTTP заголовка, которое всегда проставляется корректно.

Подозрение пало на интернет-прокси клиентов, которые по какой-то причине
не обращают внимания на Last-Modified. Интернет пестрит обилием статей,
что надо сделать, чтобы ваши веб-страницы эффективно кэшировались. Но у
меня не веб-страницы и цель у меня прямо противоположная.

В итоге, я остановился на следующем.
  1. Лучшее решение, которое 100% решает мою проблему — это скачивать
    JNLP по HTTPS. Но для этого нужен сертификат, а так же надо быть
    уверенным, что политика клиентских брандмауэров не запрещает
    использование HTTPS.
  2. Если HTTPS опция не доступна по каким либо причинам, то можно
    добавляет параметр к запросу, либо менять имя запрашиваемого файла. В
    моем случае это был не вариант, так как клиент не хотелось менять. Об
    этой тактике уже подробно писали на хабре.
  3. Самым простым с точки зрения реализации в моем случае оказалось
    решение с выставлением HTTP заголовков запрещающих кэширование. К
    сожалению, данный способ не дает 100% гарантии, так как интернет прокси
    могут с легкостью игнорировать пожелания указанные в заголовках, как в
    моем случае делали прокси двух клиентов, иногда не корректно обрабатывая
    Last-Modified заголовок.
Все же я решил попробовать указать побольше заголовков, в надежде, что
хотябы один из них не останется без внимания интернет проксей. Почитав
документацию и различные статьи, я остановился на следующем наборе:
Да не тут-то было. Оказалось что некоторые наши пользователи не
пользуются клиентским приложением для запуска JNLP, а используют для
этого IE, который не может открыть JNLP, если в ответе приходит
заголовок Cache-Control со значением no-cache или no-store. Насколько я
понял происходит это из-за того, что заголовок не дает ему сохранить
JNLP во временном хранилище, чтобы потом передать на него указатель
java-машине. Подробнее написано тут. Кстати, нашелся забавный способ обойти эту проблему: вместо того чтобы
набирать имя ресурса в адресной строке, надо сделать гиперсылку на
странице и кликнуть на неё. В этом случае IE легко выкачивает JNLP файл,
сохраняет его и запускает вебстарт.

Однако такое решение не годится, и я решил смягчить условие в
Cache-Control. В итоге мой заголовок выглядел следующим образом:
Хочу также заметить, что при реализации данного подхода изменения не
подействуют сразу, так как интернет-прокси клиента все еще хранит
страницу загруженную со старыми заголовками, так что надо сначала
дождаться, когда прокси провалидирует страницу и прочитает новые
заголовки.

До кучи приведу фрагмент кода, как я это сделал. Для обслуживания JNLP
изначально использовался стандартный JnlpDownloadServlet, так что
достаточно было добавить Filter.

web.xml
NoCacheFilter.java
Напоследок памятка, как проверить заголовки ответа телнетом:
  1. cmd
  2. telnet localhost 8888 [Enter]*
  3. HEAD /client/Application.jnlp HTTP/1.1 [Enter]
  4. Host: localhost [Enter][Enter]
* где [Enter] значит нажать одноименную клавишу