Подтвердить что ты не робот

Window.onbeforeunload ajax-запрос в Chrome

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

window.onbeforeunload = function () {
  bas_disconnect_only();
}

Функция разъединения просто отправляет HTTP-запрос GET на сторону сервера PHP script, что делает фактическую работу по отключению:

function bas_disconnect_only () {
   var xhr = bas_send_request("req=10", function () {
   });
}

Это прекрасно работает в FireFox. Но с Chrome, запрос ajax вообще не отправляется. Существует неприемлемое обходное решение: добавление предупреждения к функции обратного вызова:

function bas_disconnect_only () {
   var xhr = bas_send_request("req=10", function () {
     alert("You're been automatically disconnected.");
   });
}

После добавления вызова оповещения запрос будет отправлен успешно. Но, как вы можете видеть, это вообще не работа.

Может ли кто-нибудь сказать мне, возможно ли это с Chrome? То, что я делаю, выглядит совершенно законным для меня.

Спасибо,

4b9b3361

Ответ 1

У меня была та же проблема, когда Chrome не отправлял запрос AJAX на сервер в событие window.unload.

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

$(window).unload(function () {
   $.ajax({
     type: 'GET',
     async: false,
     url: 'SomeUrl.com?id=123'
   });
});

Этот код работает для меня в IE9, Chrome 19.0.1084.52 m и Firefox 12.

Ответ 2

Это актуально для более новых версий Chrome.

Как сказал @Garry English, отправка async запроса во время onunload страницы не будет работать, так как браузер onunload поток перед отправкой запроса. Отправка запроса на sync должна работать.

Это было верно до версии 29 Chrome, но на Chrome V 30 он внезапно перестал работать, как указано здесь.

Похоже, что единственный способ сделать это сегодня - использовать событие onbeforeunload как предлагается здесь.

НО ПРИМЕЧАНИЕ: другие браузеры вообще не позволяют отправлять запросы Ajax в событии onbeforeunload. так что вам нужно будет выполнить действие как в разгрузке, так и перед загрузкой, и проверить, было ли оно уже выполнено.

Что-то вроде этого:

var _wasPageCleanedUp = false;
function pageCleanup()
{
    if (!_wasPageCleanedUp)
    {
        $.ajax({
            type: 'GET',
            async: false,
            url: 'SomeUrl.com/PageCleanup?id=123',
            success: function ()
            {
                _wasPageCleanedUp = true;
            }
        });
    }
}


$(window).on('beforeunload', function ()
{
    //this will work only for Chrome
    pageCleanup();
});

$(window).on("unload", function ()
{
    //this will work for other browsers
    pageCleanup();
});

Ответ 3

Ознакомьтесь с методом Navigator.sendBeacon(), который был создан для этой цели.

На странице MDN говорится:

Метод navigator.sendBeacon() может использоваться для асинхронного передавать небольшие HTTP-данные из User Agent на веб-сервер.

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

Это относительно новый API и пока не поддерживается IE.

Ответ 4

Попробуйте создать переменную (желательно Boolean) и измените ее, как только вы получите ответ от вызова Ajax. И поставьте функцию bas_disconnect_only() внутри цикла while. У меня также была такая проблема, как однажды. Я думаю, это происходит потому, что Chrome не ждет вызова Ajax. Я не знаю, как я его исправил, и я не пробовал этот код, поэтому я не знаю, работает ли он. Вот пример этого:

var has_disconnected = false;
window.onbeforeunload = function () {
    while (!has_disconnected) {
        bas_disconnect_only();
        // This doesn't have to be here but it doesn't hurt to add it:
        return true;
    }
}

И внутри функции bas_send_request() (xmlhttp - это HTTP-запрос):

xmlhttp.onreadystatechange = function() {
    if (xmlhttp.readyState == 4 && xmlhttp.status == 200)
        has_disconnected = true;
}

Удачи, и я надеюсь, что это поможет.

Ответ 5

Мне приходилось отслеживать любые случаи, когда пользователь покидает страницу и отправляет ajax-запрос на бэкэнд.

var onLeavePage = function() {
    $.ajax({
        type: 'GET',
        async: false,
        data: {val1: 11, val2: 22},
        url: backend_url
    });
};

/**
 * Track user action: click url on page; close browser tab; click back/forward buttons in browser
 */
var is_mobile_or_tablet_device = some_function_to_detect();
var event_name_leave_page = (is_mobile_or_tablet_device) ? 'pagehide' : 'beforeunload';
window.addEventListener(event_name_leave_page, onLeavePage);

/**
 * Track user action when browser tab leave focus: click url on page with target="_blank"; user open new tab in browser; blur browser window etc.
 */
(/*@[email protected]*/false) ?  // check for Internet Explorer
    document.onfocusout = onLeavePage :
    window.onblur = onLeavePage;

Имейте в виду, что событие "pagehide" запускается в настольном браузере, но не срабатывает, когда пользователь нажимает кнопки "назад"/"вперед" в браузере (протестируйте в последней текущей версии Mozilla Firefox).

Ответ 6

Я искал способ, которым выход из страницы обнаруживается с помощью запроса AJAX. Это работало как каждый раз, когда я использую это, и проверяю это с MySQL. Это код (работает в Google Chrome):

    $(window).on("beforeunload", function () {
        $.ajax({
             type: 'POST',
             url: 'Cierre_unload.php',
             success: function () {
             }
        })
    })

Ответ 7

Синхронный XMLHttpRequest устарел (синхронные и асинхронные запросы). Поэтому jQuery.ajax() async: false также устарела.

Кажется невозможным (или очень трудным) использовать синхронные запросы во время до beforeunload или unload (). Поэтому рекомендуется использовать sendBeacon и я определенно согласен!

Просто:

window.addEventListener('beforeunload', function (event) {  // or 'unload'
    navigator.sendBeacon(URL, JSON.stringify({...}));

    // more safely (optional...?)
    var until = new Date().getTime() + 1000;
    while (new Date().getTime() < until);
});