Как обнаружить закрытие браузера?

В моем веб-приложении, когда пользователь входит в систему, я добавляю его Id к вектору действительных Id в сервлете, когда он выходит из системы, я удаляю его Id из вектора, чтобы я мог видеть, сколько активных пользователей активно, если пользователь забывает выйти из системы, мой сгенерированный сервлетом HTML имеет:

<meta http-equiv="Refresh" content="30; url=My_Servlet?User_Action=logout&User_Id=1111">

в теге, чтобы автоматически выйти из него.

Но я заметил, что многие пользователи всегда там, никогда не выходили из системы. Я выяснил, почему, закрыв свои браузеры, они никогда не выходили из системы вручную или автоматически, поэтому их идентификаторы никогда не будут удалены из вектора допустимых идентификаторов пользователей.

Итак, мой вопрос: как мне обнаружить, что пользователи закрывают свои браузеры, чтобы мой сервлет мог удалить их идентификаторы из вектора?


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

Список активных пользователей:

User_1 : Machine_1 [ IP_1 address ]
User_2 : Machine_2 [ IP_2 address ]
User_3 : Machine_3 [ IP_3 address ]
...

Как мне узнать от слушателя сеанса, какой сеанс пользователя завершился, и, следовательно, удалить его из моего списка?

Я надеялся, что когда сессия закончится, HttpServlet destroy() метод будет вызван, и я могу удалить там идентификатор пользователя, но он никогда не вызывается, когда пользователь закрывает свой браузер, почему? И есть ли другой метод в HttpServlet, который вызывается при закрытии сессии?

6 ответов

Решение

На стороне сервера нет способа узнать (если вы не используете JavaScript для отправки сообщения на сервер), что браузер закрыт. Как это может быть? Подумайте, как работает HTTP - все это запрос и ответ.

Однако сервер приложений будет отслеживать, когда сеансы активны, и даже сообщит вам, когда сеанс был уничтожен (например, из-за истечения времени ожидания). Посмотрите на эту страницу, чтобы увидеть, как настроить HttpSessionListener чтобы получить эти события. Тогда вы можете просто отслеживать количество активных сессий.

Количество активных сеансов будет отставать от фактического количества текущих пользователей, поскольку некоторый период (настраиваемый) времени должен истечь до истечения времени ожидания сеанса; однако, это должно быть несколько близко (вы можете уменьшить время ожидания сеанса для повышения точности), и это намного чище и проще, чем 1) отслеживание сеансов самостоятельно или 2) отправка некоторого асинхронного JavaScript на сервер, когда браузер закрыт (который не гарантированно будет отправлен).

Я предлагаю вам удалить идентификатор, когда движок сервлета уничтожает сеанс. Зарегистрировать HttpSessionListener который удаляет идентификатор пользователя, когда sessionDestroyed() называется.

Идея Диодея только поможет вам определить, что сеанс закончился более немедленно.

В JavaScript вы можете использовать onbeforeclose событие для передачи обратного вызова на сервер, когда пользователь закрывает браузер.

Я обычно использую синхронный вызов Ajax для этого.

Мне пришлось сделать это недавно, и после некоторых поисков я нашел некоторые решения в сети... все они не работают универсально!

События onbeforeclose и onclose используются для этой задачи. Но есть два улова: они запускаются, когда пользователь перезагружает страницу или даже просто меняет текущую страницу. Существуют хитрости, позволяющие узнать, действительно ли событие закрывает окно / страницу / вкладку (глядя на некоторые свойства Dom, которые теряют популярность при закрытии события), но:

  • Они зависят от браузера
  • Уловки недокументированы, поэтому хрупкие
  • И на самом деле они различаются в зависимости от версии / обновления браузера...

И что хуже всего, эти события в настоящее время игнорируются большинством современных браузеров, потому что ими злоупотребляли мошеннические объявления, появляющиеся из окон при закрытии браузера. Они не запускаются в Safari, Opera, IE7 и т. Д.

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

Решение, которое я дал, состояло в том, чтобы проверять сервер Ajax-запросом (посылая идентификатор пользователя) через регулярные промежутки времени (скажем, 1 минуту). Если сервер не получает пинг, скажем, в течение 3 минут, он отключает пользователя.

Не существует надежного способа сделать то, что вы пытаетесь сделать, но у sblundy и Diodeus есть планы, которые будут охватывать большинство обстоятельств. Вы ничего не можете сделать с кем-то, кто отключает Javascript в своем браузере, или у него отключается интернет, или отключается питание. Вы должны просто отбрасывать сессии после определенного периода бездействия (что, я думаю, и будет делать предложение Слунди прислушиваться к уничтожению сессии).

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

Добавьте дополнительные заголовки в ответ http. Когда поступают дополнительные запросы, они будут содержать эти дополнительные заголовки. Вы можете проверить наличие этих заголовков, а если их нет, вы можете прервать сеанс, поэтому начнется новый. Хотя это не "уведомляет" вас, если браузер закрыт, он может сказать вам, если кто-то закрыл свое окно и пытается вернуться, так как добавленные вами заголовки будут отсутствовать.

 wrapper.setHeader("Cache-Control", "no-cache, no-store, must-     revalidate");
 wrapper.setHeader("Pragma", "no-cache");
 wrapper.setDateHeader("Expires", 0);

 Where wrapper is a response wrapper.

 if (wrapper.getHeaderNames().size() < the number of headers you are expecting)
 request.getSession().invalidate();

 Not perfect but it might help someone.
Другие вопросы по тегам