Нет времени отправить запрос на получение при выгрузке окна

Я хочу уведомить сервер о том, что пользователь закрывает окно браузера.

Я пробовал все

$(window).bind("beforeunload", function() {
    $.get("${contextPath}/notify?direction=logout");
});

и

$(window).unload( function() {
    $.get("${contextPath}/notify?direction=logout");
});

и

$(window).unload(function() {
    $.ajax({
      url: "${contextPath}/notify?direction=logout"
    });
});

но ни то, ни другое не работает, несмотря на то, что в руководстве сказано, что, вероятно, должно.

В Firefox у меня нет уведомлений только о закрытии окна, но есть уведомления об обновлении страницы. В Chrome у меня нет ни того, ни другого.

Я попытался отследить этот скрипт в Firebug или Chrome Developer Tools и обнаружил, что он начинает работать, если отследить! Поэтому я думаю, что это не работает нормально, потому что у него нет времени на отправку запроса до закрытия окна или навигации.

Это правда? Как выполнить мою задачу?

РЕШЕНИЕ

Это сработало:

$(window).bind("beforeunload",
    function() {
        $.ajax({
            async: false,
            url: 'notify'
        });
    }
);

person Dims    schedule 10.02.2012    source источник
comment
Первая мысль: AJAX — неподходящий инструмент для работы. Вы должны использовать SJAX (синхронный), AJAX по определению освобождает поток графического интерфейса для продолжения обработки [в данном случае выгрузки].   -  person Shad    schedule 11.02.2012
comment
Посмотрите этот ответ: stackoverflow.com/a/9234785/252780   -  person Jørgen    schedule 11.02.2012


Ответы (5)


Это очень сложно, потому что браузер не будет ждать, пока придет ответ, поэтому запрос ajax может быть прерван.

Вы можете попробовать что-то подобное в событии beforeunload.

$(window).bind("beforeunload", function() {
    $.ajax({
        async: false,//This will make sure the browser waits until request completes
        url: "${contextPath}/notify?direction=logout"
    });
});
person ShankarSangoli    schedule 10.02.2012
comment
Это ненадежно, и хотя вы можете попробовать это, и это может сработать, его никогда не следует использовать в производственной среде. - person Shawn Khameneh; 11.02.2012

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

Лучшее решение — использовать navigator.sendBeacon: https://developer.mozilla.org/en-US/docs/Web/API/Navigator/sendBeacon

window.addEventListener("unload", logData, false);

function logData() {
  navigator.sendBeacon("/log", analyticsData);
}

Этот метод предназначен для кода аналитики и диагностики для отправки данных на сервер.

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

В прошлом веб-страницы пытались отложить выгрузку страницы на время, достаточное для отправки данных. Для этого они использовали обходные пути, такие как:

  • Отправка данных с блокирующим синхронным вызовом XMLHttpRequest.
  • Создание элемента и установка его src. Большинство пользовательских агентов задерживают выгрузку для загрузки изображения.
  • Создание неактивного цикла на несколько секунд.

Все эти методы блокируют выгрузку документа, что замедляет переход на следующую страницу. Следующая страница ничего не может сделать, чтобы избежать этого, поэтому новая страница кажется медленной, хотя это вина предыдущей страницы.

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

  • Данные отправляются надежно
  • Он отправляется асинхронно
  • Это не влияет на загрузку следующей страницы
person mofojed    schedule 25.06.2018
comment
Это ТОЧНО решение, которое я искал целую вечность. +1, и я бы снова проголосовал, если бы мог! - person ; 27.11.2019
comment
Наконец нашел решение после поиска в течение нескольких дней. Это очень полезно @mofojed. Большое спасибо. - person Kapila Perera; 04.03.2020
comment
Мне нравится sendBeacon. Единственный момент, который следует отметить, заключается в том, что он использует POST и не может быть изменен. - person VelLes; 14.01.2021
comment
sendBeacon теперь вызывается асинхронно. Таким образом, производительность следующей вкладки не влияет. вы можете отредактировать ответ - person phpkode; 24.05.2021
comment
@phpkode Это уже было асинхронно, фрагмент цитаты блока был со страницы MDN, объясняющей другие методы, которые были неправильными/синхронными. Однако они обновили язык на странице MDN, поэтому я обновил этот ответ, чтобы включить это. - person mofojed; 25.05.2021

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

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

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

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

person Shawn Khameneh    schedule 10.02.2012
comment
Для моей задачи не 100% надежность, потому что у меня есть решения для резервного копирования, как вы сказали. Проблема периодического опроса в том, что он не работает быстро. Поэтому мне нужно быстрое решение, которое работает с некоторыми браузерами. - person Dims; 12.02.2012

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

Представьте весь спам.

В некоторых браузерах сработает событие выгрузки, но между вашим сценарием и очисткой страницы возникнет состояние гонки.

Спасибо

person Mike Gleason jr Couturier    schedule 10.02.2012

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

Я сказал, отлично работает, верно? Ну это было только с Firefox и IE. Во многих других браузерах (таких как Opera, Safari) это не удалось.

Так что мой добрый совет — не зависеть от этих функций, так как они зависят только от браузера.

person Shankar Narayana Damodaran    schedule 10.02.2012