webentwicklung-frage-antwort-db.com.de

JavaScript, Browser, Fenster schließen - senden Sie eine AJAX Fordern Sie beim Schließen des Fensters ein Skript an oder führen Sie es aus

Ich versuche herauszufinden, wann ein Benutzer eine bestimmte Seite verlassen hat. Es ist kein Problem herauszufinden, wann er einen Link innerhalb der Seite zum Navigieren verwendet hat, aber ich muss etwas markieren, als er das Fenster geschlossen oder eine andere URL eingegeben und die Eingabetaste gedrückt hat. Der zweite ist nicht so wichtig, aber der erste ist. Also hier ist die Frage:

Wie kann ich sehen, wann ein Benutzer meine Seite geschlossen hat (capture window.close event), und dann ... spielt es keine Rolle (ich muss eine AJAX -Anforderung senden, aber ob ich sie erhalten kann) Alarm auslösen, ich kann den Rest erledigen).

21
zozo

Es gibt unload- und beforeunload-JavaScript-Ereignisse, die jedoch für eine Ajax-Anforderung nicht zuverlässig sind (es kann nicht garantiert werden, dass eine in einem dieser Ereignisse initiierte Anforderung den Server erreicht).

Aus diesem Grund ist dies in hohem Maße nichtempfohlen, und Sie sollten nach einer Alternative suchen.

Wenn Sie dies auf jeden Fall benötigen, ziehen Sie eine Lösung im Ping-Stil in Betracht. Senden Sie jede Minute eine Anfrage und teilen Sie dem Server mit, dass ich immer noch hier bin. Wenn der Server länger als zwei Minuten keine solche Anforderung erhält (Sie müssen Latenzen usw. berücksichtigen), wird der Client als offline betrachtet.


Eine andere Lösung wäre, unload oder beforeunload zu verwenden, um eine Sjax-Anforderung (synchrones JavaScript und XML) auszuführen. Dies wird jedoch nicht empfohlen. Wenn Sie dies tun, wird der Browser des Benutzers grundsätzlich eingefroren, bis die Anforderung vollständig ist. Dies wird dem Benutzer nicht gefallen (auch wenn die Anforderung nur wenig Zeit in Anspruch nimmt).

31
Felix

Gestützt auf andere Antwort .

2018 ist die Beacon-API die Lösung für dieses Problem (in fast jedem Browser ).

Beacon-Anforderungen werden garantiert eingeleitet, bevor eine Seite entladen wird, und werden vollständig ausgeführt, ohne dass eine Blockierungsanforderung erforderlich ist.

Sie können es innerhalb des Ereignisses onunload verwenden und sicher sein, dass es gesendet wird.

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

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

    navigator.sendBeacon(URL, data);

});

Großartiger Blog-Beitrag: http://usefulangle.com/post/62/javascript-send-data-to-server-on-page-exit-reload-redirect

Beacon API: https://developer.mozilla.org/en-US/docs/Web/API/Beacon_API/Using_the_Beacon_API

10
Baishu

1) Wenn Sie nach einer Möglichkeit suchen, in allen Browsern zu arbeiten, ist es am sichersten, ein synchrones AJAX an den Server zu senden. Dies ist keine gute Methode. Stellen Sie jedoch sicher, dass Sie nicht zu viele Daten an den Server senden und der Server schnell ist.

2) Sie können auch eine asynchrone AJAX -Anforderung verwenden und die Funktion ignore_user_abort auf dem Server verwenden (wenn Sie PHP verwenden). Allerdings hängt ignore_user_abort stark von der Serverkonfiguration ab. Stellen Sie sicher, dass Sie es gut testen.

3) Bei modernen Browsern sollten Sie keine AJAX -Anforderung senden. Sie sollten die neue Methode navigator.sendBeacon verwenden, um Daten asynchron an den Server zu senden, ohne das Laden der nächsten Seite zu blockieren. Da Sie Daten an den Server senden möchten, bevor der Benutzer die Seite verlässt, können Sie diese Methode in einem unload -Ereignishandler verwenden.

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

Es scheint auch eine Polyfill für sendBeacon zu geben. Es wird auf das Senden eines synchronen AJAX zurückgegriffen, wenn die Methode nicht standardmäßig verfügbar ist.

WICHTIG FÜR MOBILE GERÄTE: Bitte beachten Sie, dass der Ereignishandler Entladen nicht für mobile Geräte ausgelöst werden kann . Das Ereignis Sichtbarkeitsänderung wird jedoch garantiert ausgelöst. Für mobile Geräte muss der Code für die Datenerfassung möglicherweise etwas angepasst werden.

In meinem Blogartikel finden Sie die Code-Implementierung aller drei Möglichkeiten.

10
Useful Angle

Ich wollte auch die gleiche Funktionalität erreichen und bin auf diese Antwort von Felix gestoßen ( Es ist nicht garantiert, dass eine in einem dieser Ereignisse initiierte Anfrage den Server erreichen wird ).

Damit die Anfrage den Server erreicht, haben wir versucht, den folgenden Code zu verwenden: -

onbeforeunload = function() {

    //Your code goes here.

    return "";
} 

Wir verwenden den IE Browser. Wenn der Benutzer den Browser schließt, wird der Bestätigungsdialog aufgrund von return ""; angezeigt. Er wartet auf die Bestätigung des Benutzers. Diese Wartezeit veranlasst die Anforderung, den Server zu erreichen.

3
Pradeep Yadav

Ich stimme Felix Idee zu und ich habe mein Problem mit dieser Lösung gelöst und jetzt möchte ich die serverseitige Lösung löschen:

1.Senden Sie eine Anfrage von der Client-Seite an den Server

2.Speichere die Zeit der letzten Anforderung, die in einer Variablen empfangen wurde

3.Überprüfen Sie die Serverzeit und vergleichen Sie sie mit der Variablen der zuletzt empfangenen Anforderung

4.Wenn das Ergebnis die erwartete Zeit überschreitet, starten Sie den Code, den Sie ausführen möchten, wenn Windows geschlossen wird.

0
Ramin Farajpour

Probier diese. Ich habe dieses Problem in Javascript gelöst, indem ich einen Ajax-Aufruf an den Server beim Durchsuchen oder Schließen von Registerkarten gesendet habe. Ich hatte ein Problem mit dem Aktualisieren der Seite, da die Funktion onbeforeunload einschließlich des Aktualisierens der Seite aktiviert war. performance.navigation.type == 1 sollte die Aktualisierung vom Schließen isolieren (im Mozzila-Browser).

$(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
   });
}
0
Stidljivi

Jahre nach dem Posten der Frage habe ich eine bessere Implementierung vorgenommen, einschließlich nodejs und socket.io ( https://socket.io ) (Sie können für diese Angelegenheit jede Art von Socket verwenden, aber das war meine persönliche Wahl ).

Grundsätzlich öffne ich eine Verbindung mit dem Client, und wenn er auflegt, speichere ich nur Daten/tue, was immer ich brauche. Offensichtlich kann dies nicht verwendet werden, um irgendetwas zu zeigen/den Client umzuleiten (da Sie es serverseitig tun), aber es ist das, was ich damals tatsächlich brauchte.

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

Also ... heutzutage denke ich, dass dies ein besserer Ansatz wäre (der zwar schwieriger zu implementieren ist, weil Sie Knoten, Socket usw. benötigen, aber nicht so schwer ist; sollte etwa 30 Minuten dauern, wenn Sie ihn zum ersten Mal durchführen) als der Version entladen.

0
zozo

Die ausgewählte Antwort ist richtig, da Sie nicht garantieren können, dass der Browser die xhr-Anforderung sendet. Abhängig vom Browser können Sie jedoch zuverlässig eine Anforderung beim Schließen von Registerkarten oder Fenstern senden.

Normalerweise wird der Browser geschlossen, bevor xhr.send () ausgeführt wird. Chrome und Edge scheinen zu warten, bis die JavaScript-Ereignisschleife leer ist, bevor sie das Fenster schließen. Sie lösen die xhr-Anforderung auch in einem anderen Thread als der JavaScript-Ereignisschleife aus. Dies bedeutet, dass, wenn Sie die Ereignisschleife lange genug voll halten können, der xhr erfolgreich ausgelöst wird. Zum Beispiel habe ich getestet, wie ich eine xhr-Anfrage gesendet habe und dann bis 100.000.000 gezählt habe. Dies funktionierte sowohl in Chrom als auch in Edge für mich sehr konsequent. Wenn Sie anglejs verwenden, bewirkt das Umbrechen Ihres Aufrufs von $ http in $ apply dasselbe.

IE scheint ein bisschen anders zu sein. Ich glaube nicht, dass IE darauf wartet, dass die Ereignisschleife leer ist oder dass der aktuelle Stack-Frame leer ist. Zwar wird gelegentlich eine Anfrage korrekt gesendet, doch weitaus häufiger (in 80% -90% der Fälle) wird IE das Fenster oder die Registerkarte schließen, bevor die xhr-Anfrage vollständig ausgeführt wurde führen dazu, dass nur eine Teilnachricht gesendet wird. Grundsätzlich erhält der Server eine Post-Anfrage, aber es gibt keinen Body.

Für die Nachwelt ist hier der Code, den ich als window.onbeforeunload Listener-Funktion verwendet habe:

  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++) {}

Ich habe getestet in:

Chrome 61.0.3163.100

IE 11.608.15063.0CO

Edge 40.15063.0.0

0
codepuzzler