JavaScript, браузеры, закрытие окна - отправьте запрос AJAX или запустите скрипт при закрытии окна - PullRequest
23 голосов
/ 28 мая 2011

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

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

Ответы [ 7 ]

31 голосов
/ 28 мая 2011

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

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

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


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

18 голосов
/ 04 ноября 2017

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);
});

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

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

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

14 голосов
/ 24 февраля 2018

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

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

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

Вы можете использовать его внутри события 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

3 голосов
/ 24 февраля 2015

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

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

onbeforeunload = function() {

    //Your code goes here.

    return "";
} 

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

0 голосов
/ 26 октября 2017

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

Обычно браузерзакрывается до фактического выполнения xhr.send ().Chrome и ребро выглядят так, как будто они ждут, пока цикл событий 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++) {}

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

Chrome 61.0.3163.100

IE 11.608.15063.0CO

Edge 40.15063.0.0

0 голосов
/ 08 марта 2014

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

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

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

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

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

0 голосов
/ 28 мая 2011

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

<body onUnload="javascript:">

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

...