web-dev-qa-db-fra.com

window.onbeforeunload ajax request in Chrome

J'ai une page Web qui gère le contrôle à distance d'une machine via Ajax. Lorsque l'utilisateur quitte la page, je souhaite me déconnecter automatiquement de la machine. Voici donc le code:

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

La fonction de déconnexion envoie simplement une requête HTTP GET à un PHP côté serveur, qui fait le travail réel de déconnexion:

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

Cela fonctionne bien dans FireFox. Mais avec Chrome, la demande ajax n'est pas envoyée du tout. Il existe une solution de contournement inacceptable: ajouter une alerte à la fonction de rappel:

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

Après avoir ajouté l'appel d'alerte, la demande serait envoyée avec succès. Mais comme vous pouvez le voir, ce n'est pas du tout une solution.

Quelqu'un pourrait-il me dire si cela est réalisable avec Chrome? Ce que je fais me semble tout à fait légitime.

Merci,

46
lang2

J'avais le même problème, où Chrome n'envoyait pas la demande AJAX au serveur dans l'événement window.unload.

Je n'ai pu le faire fonctionner que si la demande était synchrone. J'ai pu le faire avec Jquery et en définissant la propriété async sur false:

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

Le code ci-dessus fonctionne pour moi dans IE9, Chrome 19.0.1084.52 m et Firefox 12.

40
Garry English

Cela s'applique aux nouvelles versions de Chrome.

Comme @Garry English said , l'envoi d'une demande async pendant la page onunload ne fonctionnera pas, car le navigateur tuera le thread avant d'envoyer la demande. L'envoi d'une demande sync devrait cependant fonctionner.

C'était juste jusqu'à la version 29 de Chrome, mais sur Chrome V 30, il a soudainement cessé de fonctionner comme indiqué ici .

Il semble que la seule façon de procéder aujourd'hui est d'utiliser l'événement onbeforeunloadcomme suggéré ici .

MAIS NOTE: les autres navigateurs ne vous laisseront pas du tout envoyer des demandes Ajax dans l'événement onbeforeunload. vous devrez donc effectuer l'action à la fois au déchargement et au déchargement, et vérifier si elle a déjà eu lieu.

Quelque chose comme ça:

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();
});
67
Mohoch

Récupérez la méthode Navigator.sendBeacon () qui a été construite à cet effet.

La page MDN dit:

La méthode navigator.sendBeacon () peut être utilisée pour transférer de manière asynchrone de petites données HTTP de l'agent utilisateur vers un serveur Web.

Cette méthode répond aux besoins du code d'analyse et de diagnostic qui tente généralement d'envoyer des données à un serveur Web avant le déchargement du document. L'envoi des données plus tôt peut entraîner une occasion manquée de recueillir des données. Cependant, garantir que les données ont été envoyées pendant le déchargement d'un document est quelque chose qui a toujours été difficile pour les développeurs.

Il s'agit d'une API relativement récente et ne semble pas encore prise en charge par IE.

19
Sparky

Essayez de créer une variable (booléenne de préférence) et de la faire changer une fois que vous obtenez une réponse de l'appel Ajax. Et placez la fonction bas_disconnect_only() dans une boucle while. J'ai également eu un problème comme celui-ci une fois. Je pense que cela se produit parce que Chrome n'attend pas l'appel Ajax. Je ne sais pas comment je l'ai corrigé et je n'ai pas essayé ce code donc je ne sais pas s'il le fait Voici un exemple:

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

Et à l'intérieur de la fonction bas_send_request() (xmlhttp se trouve la requête HTTP):

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

Bonne chance et j'espère que cela vous aidera.

3
Metod Medja

Synchronous XMLHttpRequest est obsolète ( requêtes synchrones et asynchrones ). Par conséquent, l'option async: false De jQuery.ajax() est également déconseillée.

Il semble impossible (ou très difficile) d'utiliser des requêtes synchrones pendant beforeunload ou unload ( Ajax Synchronous Request Failing in Chrome ). Il est donc recommandé d'utiliser sendBeacon et je suis définitivement d'accord!

Simplement:

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);
});
0
GyuHyeon Choi

J'ai dû suivre tous les cas où l'utilisateur quitte la page et envoyer une demande ajax au backend.

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.
 */
(/*@cc_on!@*/false) ?  // check for Internet Explorer
    document.onfocusout = onLeavePage :
    window.onblur = onLeavePage;

Sachez que l'événement "pagehide" se déclenche dans le navigateur du bureau, mais il ne se déclenche pas lorsque l'utilisateur clique sur les boutons Précédent/Suivant dans le navigateur (test dans la dernière version actuelle de Mozilla Firefox).

0
sNICkerssss

J'ai cherché un moyen de détecter la sortie de la page avec la requête AJAX . Cela a fonctionné comme chaque fois que je l'utilise, et vérifiez-le avec MySQL. Voici le code (travaillé dans Google Chrome):

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