JavaScript, браузеры, закрытие окна - отправьте запрос AJAX или запустите скрипт при закрытии окна

Я пытаюсь выяснить, когда пользователь покинул указанную страницу. Нет проблем с поиском, когда он использовал ссылку внутри страницы для навигации, но мне нужно что-то отметить, например, когда он закрыл окно или набрал другой URL и нажал клавишу ввода. Второй не так важен, но первый. Итак, вот вопрос:

Как я могу увидеть, когда пользователь закрыл мою страницу (захват события window.close), а затем... на самом деле не имеет значения (мне нужно отправить запрос AJAX, но если я смогу заставить его запустить оповещение, я могу сделай все остальное).

7 ответов

Решение

Есть unload а также beforeunload события javascript, но они не являются надежными для запроса Ajax (не гарантируется, что запрос, инициированный в одном из этих событий, достигнет сервера).

Поэтому делать это крайне не рекомендуется, и вы должны искать альтернативу.

Если вам это определенно необходимо, рассмотрите решение в стиле "ping". Отправляйте запрос каждую минуту, в основном говоря серверу "Я все еще здесь". Затем, если сервер не получает такой запрос более двух минут (необходимо учитывать задержки и т. Д.), Клиент считается отключенным.


Другое решение было бы использовать unload или же beforeunload сделать запрос Sjax (синхронный JavaScript и XML), но это совершенно не рекомендуется. Делая это, вы в основном замораживаете браузер пользователя до тех пор, пока запрос не будет выполнен, что им не понравится (даже если запрос занимает мало времени).

Основываясь на другом ответе.

Чтобы прояснить ситуацию, в 2018 году API-интерфейс Beacon является решением этой проблемы ( практически во всех браузерах)

Запросы маяка гарантированно инициируются до того, как страница выгружена, и они выполняются до конца, не требуя запроса на блокировку.

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

$(window).on('unload', function() {

    var URL = "https://example.com/foo";
    var data = "bar";

    navigator.sendBeacon(URL, data);

});

Отличное сообщение в блоге: http://usefulangle.com/post/62/javascript-send-data-to-server-on-page-exit-reload-redirect

API маяка: https://developer.mozilla.org/en-US/docs/Web/API/Beacon_API/Using_the_Beacon_API

1) Если вы ищете способ работы во всех браузерах, то самый безопасный способ - отправить синхронный AJAX на сервер. Это не очень хороший метод, но, по крайней мере, убедитесь, что вы не отправляете слишком много данных на сервер, и сервер работает быстро.

2) Вы также можете использовать асинхронный AJAX-запрос и использовать функцию ignore_user_abort на сервере (если вы используете PHP). Однако ignore_user_abort во многом зависит от конфигурации сервера. Удостоверьтесь, что вы проверяете это хорошо.

3) Для современных браузеров не следует отправлять запрос AJAX. Вам следует использовать новый метод navigator.sendBeacon для асинхронной отправки данных на сервер без блокировки загрузки следующей страницы. Поскольку вы хотите отправить данные на сервер до того, как пользователь уйдет со страницы, вы можете использовать этот метод в обработчике события unload.

$(window).on('unload', function() {
    var fd = new FormData();
    fd.append('ajax_data', 22);
    navigator.sendBeacon('ajax.php', fd);
});

Там также, кажется, есть polyfill для sendBeacon. Он прибегает к отправке синхронного AJAX, если метод не доступен изначально.

ВАЖНО ДЛЯ МОБИЛЬНЫХ УСТРОЙСТВ: обратите внимание, что обработчик события unload не гарантированно будет запущен для мобильных телефонов. Но событие visibilitychange гарантированно будет запущено. Так что для мобильных устройств ваш код сбора данных может потребовать небольшой настройки.

Вы можете обратиться к моей статье в блоге для реализации кода всеми тремя способами.

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

Чтобы запрос дошел до сервера, мы попробовали следующий код:-

onbeforeunload = function() {

    //Your code goes here.

    return "";
} 

Мы используем браузер IE и теперь, когда пользователь закрывает браузер, он получает диалог подтверждения из-за return ""; & ожидает подтверждения пользователя и это время ожидания делает запрос на доступ к серверу.

Спустя годы после публикации вопроса я улучшил реализацию, включая nodejs и socket.io ( https://socket.io/) (вы можете использовать любой сокет в этом отношении, но это был мой личный выбор).

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

 io.on('connection', function(socket){
      socket.on('disconnect', function(){
          // Do stuff here
      });
 });

Итак... в настоящее время я думаю, что это было бы лучше (хотя и сложнее реализовать, потому что вам нужен узел, сокет и т. Д., Но это не так сложно; должно занять около 30 минут, если вы делаете это в первый раз) подход, чем подход выгрузить версию.

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

Обычно браузер закрывается до фактического выполнения xhr.send(). Chrome и edge выглядят так, как будто они ждут, пока цикл событий javascript опустеет, прежде чем закрывать окно. Они также запускают запрос xhr в другом потоке, нежели цикл событий javascript. Это означает, что если вы сможете поддерживать цикл событий достаточно долго, xhr будет успешно запущен. Например, я протестировал отправку запроса xhr, а затем подсчитал до 100 000 000. Это работало очень последовательно и в хроме и в крае для меня. Если вы используете angularjs, завершение вызова в $http в $apply делает то же самое.

IE кажется немного другим. Я не думаю, что IE ждет, пока цикл событий опустеет, или даже текущий кадр стека опустеет. Хотя иногда он правильно отправляет запрос, кажется, что гораздо чаще (80%-90% времени) происходит то, что IE закрывает окно или вкладку до полного выполнения запроса xhr, что приводит только к частичному сообщению. послан. В основном сервер получает почтовый запрос, но тела нет.

Для потомков вот код, который я использовал в качестве функции прослушивателя window.onbeforeunload:

  var xhr = new XMLHttpRequest();
  xhr.open("POST", <your url here>);
  xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
  var payload = {id: "123456789"};
  xhr.send(JSON.stringify(payload));

  for(var i = 0; i < 100000000; i++) {}

Я тестировал в:

Хром 61.0.3163.100

IE 11.608.15063.0CO

Край 40.15063.0.0

Попробуй это. Я решил эту проблему в javascript, отправив вызов ajax на сервер при просмотре или закрытии вкладки. У меня возникла проблема с обновлением страницы из-за функции onbeforeunload, включающей обновление страницы. performance.navigation.type == 1 должен изолировать обновление от закрытия (в браузере mozzila).

$(window).bind('mouseover', (function () { // detecting DOM elements
    window.onbeforeunload = null;
}));

$(window).bind('mouseout', (function () { //Detecting event out of DOM
      window.onbeforeunload = ConfirmLeave;
}));

function ConfirmLeave() {
   if (performance.navigation.type == 1) { //detecting refresh page(doesnt work on every browser)
   }
   else {
       logOutUser();
   }
}

$(document).bind('keydown', function (e) { //detecting alt+F4 closing
    if (e.altKey && e.keyCode == 115) {
        logOutUser();
    }    
});
function logOutUser() {
   $.ajax({
     type: "POST",
     url: GWA("LogIn/ForcedClosing"), //example controller/method
     async: false
   });
}

Я согласен с идеей Феликса, и я решил свою проблему с этим решением, и теперь я хочу очистить решение на стороне сервера:

1. отправить запрос со стороны клиента на сервер

2. время последнего запроса, полученного в переменной

3. Проверьте время сервера и сравните его по переменной последнего полученного запроса.

4.Если результат больше ожидаемого времени, начните запускать код, который хотите запустить, когда окна закрыты...

Использование:

<body onUnload="javascript:">

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

Другие вопросы по тегам