expertenaustausch > comp.lang.* > comp.lang.javascript

Ralph Stahl (05.12.2018, 15:37)
Moin!

Ich möchte erreichen, dass beim Schließen eines Browserfensters über das
Kreuzchen rechts oben als letzte Amtshandlung die im Browser laufende
Anwendung noch ordentlich geschlossen wird (Session schließen etc). Nach
zum Beispiel [1] sollte das durch das Abfangen des onunload-Events
passieren können. Mir schwebt vor, das so ähnlich zu tun:

$(document).ready(function () {

window.unload = function () {
$.post('funktion.php');
};
...
}

In funktion.php soll soll u.a. protokolliert werden, dass ich hier
"vorbei gekommen" bin (das ist erprobt). Aber es passiert nichts. Auch
nicht mit onbeforeunload nach [2].

Ein anderes Beispiel fand ich bei stackoverflow [3], ich habs etwas
abgewandelt, aber das tut auch nichts:

<html>
<body>
<script>

function goodBye(evt) {
console.log('unload');
return 'good bye';
}

window.onbeforeunload = goodBye;

</script>
</body>
</html>

Warum bewirkt das alles nichts?

Nun habe ich allerdings auch ein technisches Verständnisproblem. Wie
funktioniert es, dass ein Browser-Tab oder das ganze Fenster (was ja vom
System dargestellt wird!) noch etwas tun kann, sobald es abgeschossen
wird oder sogar (im zweiten Fall) sobald es *gleich* abgeschossen werden
wird? Ist das nicht á la Münchhausen? Ich könnte ja im ersten Beispiel
auch statt $.post() einfach alert('huhu') schreiben - aber wer soll das
darstellen, wenn das Fenster zu geht oder schon zu ist?

Ich würde mich sehr über Hinweise freuen. Ehrlich gesagt weiß ich nicht
so recht, wie ich Frau Goggel gezielter fragen soll...

Ralph

[1]
[2]
[3]
Thomas 'PointedEars' Lahn (05.12.2018, 23:35)
Ralph Stahl wrote:
[..]
> </body>
> </html>
> Warum bewirkt das alles nichts?


1. <http://glasgoogle.de/> (leider ist unsere FAQ etwas angestaubt)

2. Das ist kein gültiges HTML(5): <http://validator.w3.org/>

3. Du schreibst auch nicht, mit welchem/-n Umgebungen Du getestet hast.

Vermutlich geht es zumindest teilweise nicht zum Schutz des Benutzers (was
zeigt die Fehlerkonsole?). Wäre das nämlich möglich, was Du willst, dann
könnte jede Website, ohne dass der Benutzer das beeinflussen kann, beim
Wegnavigieren noch schnell irgendwelche Daten absenden, und der Benutzer
müsste warten, bis das geschehen wäre (oder definitiv fehlschlüge).

Diese beiden Events (“unload” und “beforeunload”) werden nämlich nicht nur
gefeuert, wenn das Browserfenster bzw. der Browser-Tab geschlossen wird.

Dass in unload- und beforeunload-Listenern nicht alles funktioniert, ist
bekannt. Besonders in Firefox sind hier zum Schutz des Benutzers die
Möglichkeiten für Webentwickler stark eingeschränkt. Was sicher geht ist
das Gezeigte: im onbeforeunload-Listener einen String zurückgeben, mit dem
der Benutzer gefragt werden kann, ob er wirklich wegnavigieren will.

Beim unload-Event ist es eventuell auch schon zu spät, weil relevante
Objekte schon nicht mehr verfügbar sind oder währenddessen abgeräumt werden.
In jedem Fall ist es eine Race Condition.

<https://javascript.info/onload-ondomcontentloaded>

Sessions lässt man am besten bei Logout oder mit Timeout expiren
(Session-Cookies und Server-Sessions), da man sich nicht darauf verlassen
kann, dass clientseitiges Scripting verwendet wird.

Übrigens ist jQuery hierfür Overkill; daher das einfache Beispiel auf
Stack Overflow.

> [1]
> [2]


*Alle* Bookmarks mit URI-Präfix “
*löschen* und ersetzen durch die äquivalenten mit Präfix
<https://developer.mozilla.org/>.

JETZT. SOFORT.

<https://www.w3fools.com/>
Ralph Stahl (06.12.2018, 15:24)
Das Problem ist bereits gelöst, siehe unten.

Thomas 'PointedEars' Lahn schrieb:
> Ralph Stahl wrote:
> 1. <http://glasgoogle.de/> (leider ist unsere FAQ etwas angestaubt)


Leider wusste ich nicht genau, wie ich was fragen und suchen sollte,
deswegen die unschöne Fragestellung :-).
> 2. Das ist kein gültiges HTML(5): <http://validator.w3.org/>


Weiß ich, taugt aber als Beispiel zum Reden :-).

> 3. Du schreibst auch nicht, mit welchem/-n Umgebungen Du getestet hast.


Nur Firefox, darin soll eine bestimmte Anwendung laufen, ist so vereinbart.

> Vermutlich geht es zumindest teilweise nicht zum Schutz des Benutzers (was
> zeigt die Fehlerkonsole?). Wäre das nämlich möglich, was Du willst, dann
> könnte jede Website, ohne dass der Benutzer das beeinflussen kann, beim
> Wegnavigieren noch schnell irgendwelche Daten absenden, und der Benutzer
> müsste warten, bis das geschehen wäre (oder definitiv fehlschlüge).


Genau das tut die gefundene Lösung nun. Auszug:

$(document).ready(function () {
$(window).on('unload', function () {
$.ajax({
'url': 'meineaktionen.php',
'async': false
//
});
...
});

Entscheidend ist das 'async':false, weil eben sonst der Tab/Browser weg
wäre, bevor die Aktion ausgeführt werden konnte. In meinefunktionen.php
wird z.B. die laufende Session gekillt, das ist hier wichtig.

> Diese beiden Events (?unload? und ?beforeunload?) werden nämlich nicht nur
> gefeuert, wenn das Browserfenster bzw. der Browser-Tab geschlossen wird.


Ja, auch beim Reload, zumindest "beforeunload", das weiß ich.

[..]
> Sessions lässt man am besten bei Logout oder mit Timeout expiren
> (Session-Cookies und Server-Sessions), da man sich nicht darauf verlassen
> kann, dass clientseitiges Scripting verwendet wird.


Gewiss. Hier muss es aber eben auch gehen, wenn das Fenster einfach
geschlossen wird. Das tut es nun.

> Übrigens ist jQuery hierfür Overkill; daher das einfache Beispiel auf
> Stack Overflow.

Nur funktionieren diese eben nicht, deswegen frage ich ja. Entscheidend
ist wie gesagt das async, was mit trivialem Javascript nicht als
Zweizeiler geht. Außerdem habe ich sowieso jQuery, da kann ich es auch
nutzen.

Ralph
Christoph M. Becker (06.12.2018, 16:35)
Am 06.12.2018 um 14:24 schrieb Ralph Stahl:

> Thomas 'PointedEars' Lahn schrieb:
> Nur funktionieren diese eben nicht, deswegen frage ich ja. Entscheidend
> ist wie gesagt das async, was mit trivialem Javascript nicht als
> Zweizeiler geht. Außerdem habe ich sowieso jQuery, da kann ich es auch
> nutzen.


Siehe
<https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Synchronous_and_Asynchronous_Requests#Synchronous_ request>.
Thomas 'PointedEars' Lahn (06.12.2018, 18:21)
Ralph Stahl wrote:
> Das Problem ist bereits gelöst,


Nein, Du hast nur ein neues Problem erzeugt.

> siehe unten.


Ja, genau.

> Thomas 'PointedEars' Lahn schrieb:
>> 3. Du schreibst auch nicht, mit welchem/-n Umgebungen Du getestet hast.

> Nur Firefox, darin soll eine bestimmte Anwendung laufen, ist so vereinbart.


Das ist immer noch eine unzureichende Angabe. Welche Version von Firefox,
welches Betriebssystem?

>> Vermutlich geht es zumindest teilweise nicht zum Schutz des Benutzers (was
>> zeigt die Fehlerkonsole?). Wäre das nämlich möglich, was Du willst, dann
>> könnte jede Website, ohne dass der Benutzer das beeinflussen kann, beim
>> Wegnavigieren noch schnell irgendwelche Daten absenden, und der Benutzer
>> müsste warten, bis das geschehen wäre (oder definitiv fehlschlüge).

> Genau das tut die gefundene Lösung nun.


Und zusätzlich blockiert sie im Worst Case den Browser komplett, zumindest
aber den entsprechenden Browser-Tab bzw. das -Fenster.

[..]
> });
> Entscheidend ist das 'async':false, weil eben sonst der Tab/Browser weg
> wäre, bevor die Aktion ausgeführt werden konnte.


Und weil das im Worst Case den Browser komplett blockiert, ist dies
deprecated und demnächst wird die Unterstützung dafür entfernt werden.
So zumindest die Aussage einiger Browserhersteller.

Sieht man deshalb als Warnung in den Chrome Dev Tools (Chromium, Chrome)
in der Script-Console, vermutlich auch in Firefox.

Es ist deshalb zu erwarten, dass das zuerst in onbeforeunload/onunload nicht
mehr funktionieren wird.

> In meinefunktionen.php wird z.B. die laufende Session gekillt, das ist hier wichtig.


Das ist Unsinn, wie bereits erklärt.

>> Diese beiden Events (“unload” und “beforeunload”) werden nämlich nicht nur
>> gefeuert, wenn das Browserfenster bzw. der Browser-Tab geschlossen wird.

> Ja, auch beim Reload, zumindest "beforeunload", das weiß ich.


Du nimmst also in Kauf, dass der Benutzer seinen Browser nicht benutzen
kann, bis sich Dein Server mal bequemt, zu antworten (oder es irgendwann
doch einen Timeout gibt).

>> Sessions lässt man am besten bei Logout oder mit Timeout expiren
>> (Session-Cookies und Server-Sessions), da man sich nicht darauf verlassen
>> kann, dass clientseitiges Scripting verwendet wird.

> Gewiss. Hier muss es aber eben auch gehen, wenn das Fenster einfach
> geschlossen wird.


Nein, das muss es nicht. Man setzt einfach ein Session-Cookie, das wird
dann automagisch vom Browser weggeräumt. Und auf dem Server setzt man das
Session-Expire nicht auf den Sanktnimmerleinstag, sondern z. B. auf 2
Stunden. Wenn im eingeloggten Zustand eine Aktion stattfindet, macht man
ein Session-Refresh.

>> Übrigens ist jQuery hierfür Overkill; daher das einfache Beispiel auf
>> Stack Overflow.

> Nur funktionieren diese eben nicht,


Doch, das tun sie. Du hast nur keine Ahnung, was Du tust.

PointedEars (ZCE PHP)
Stefan Reuther (06.12.2018, 19:57)
Am 06.12.2018 um 14:24 schrieb Ralph Stahl:
[..]
> Entscheidend ist das 'async':false, weil eben sonst der Tab/Browser weg
> wäre, bevor die Aktion ausgeführt werden konnte. In meinefunktionen.php
> wird z.B. die laufende Session gekillt, das ist hier wichtig.


Das verlässt sich drauf, dass der Browser dich im onunload noch Dinge
tun lässt, die Zeit brauchen. Darauf würde ich mich nicht verlassen.

Im Zweifelsfall hat der Nutzer den Browser per Taskmanager beendet (zum
Beispiel, weil er davon genervt war, dass der Browser in einem
synchronen XMLHTTPRequest hing), da wird ein onunload sowieso nicht
ausgeführt.

Besser wäre da eine Lösung, wo der Browser extra eine Socketverbindung
zum Server aufbaut. Wenn das Browserfenster geschlossen wird, egal aus
welchem Grund, wird die Socketverbindung geschlossen; daran kann die
Serverseite erkennen, dass die Session beendet ist. Eine Möglichkeit
wäre ein Websocket. Das braucht serverseitig aber ein wenig mehr als nur
ein paar php-Skripte.

Eine andere Lösung wäre, z.B. alle 10s ein Ping an die Webseite zu
schicken. Empfängt der Server für 30s kein Ping, ist die Session
beendet. Das ist auch mit normalen php-Skripten realisierbar, und ist
speziell im lokalen Netzwerk durchaus vertretbar.

Stefan
Thomas 'PointedEars' Lahn (06.12.2018, 22:22)
Stefan Reuther wrote:
> Besser wäre da eine Lösung, wo der Browser extra eine Socketverbindung
> zum Server aufbaut. Wenn das Browserfenster geschlossen wird, egal aus
> welchem Grund, wird die Socketverbindung geschlossen; daran kann die
> Serverseite erkennen, dass die Session beendet ist. Eine Möglichkeit
> wäre ein Websocket. Das braucht serverseitig aber ein wenig mehr als nur
> ein paar php-Skripte.


Ich wollte eigentlich schreiben:

Konkret braucht es einen veralteten Browser oder einen sehr versierten
Benutzer, da man sich entschieden hat, WebSocket-Unterstützung aus
Sicherheitsgründen entweder per Default zu deaktivieren oder wieder zu
entfernen.

Jedoch bezieht sich das nur auf eine ältere Version des Protokolls.
Offenbar wird WebSocket (neue Version) inzwischen weithin unterstützt:

<https://caniuse.com/#search=websocket>

(siehe Fussnote 1)

> Eine andere Lösung wäre, z.B. alle 10s ein Ping an die Webseite zu
> schicken. Empfängt der Server für 30s kein Ping, ist die Session
> beendet. Das ist auch mit normalen php-Skripten realisierbar, und ist
> speziell im lokalen Netzwerk durchaus vertretbar.


Aber unnötig, da Session-Cookies automagisch beim Beenden des Browsers
gelöscht werden. Dann gibt es zwar noch (bis zum Timeout) die
Server-Session, aber keine Möglichkeit mehr, darauf zuzugreifen. Also alles
im grünen Bereich, oder?
Stefan Reuther (07.12.2018, 20:47)
Am 06.12.2018 um 21:22 schrieb Thomas 'PointedEars' Lahn:
> Stefan Reuther wrote:
> Ich wollte eigentlich schreiben:
> Konkret braucht es einen veralteten Browser oder einen sehr versierten
> Benutzer, da man sich entschieden hat, WebSocket-Unterstützung aus
> Sicherheitsgründen entweder per Default zu deaktivieren oder wieder zu
> entfernen.
> Jedoch bezieht sich das nur auf eine ältere Version des Protokolls.
> Offenbar wird WebSocket (neue Version) inzwischen weithin unterstützt:
> <https://caniuse.com/#search=websocket>


Seit 5 Jahren, wenn ich die Werte richtig parse. Kann man also nehmen,
insbesondere, wenn's fürs Intranet ist und man nicht mit Usern aus dem
zentralafrikanischen Busch rechnen muss.

> Aber unnötig, da Session-Cookies automagisch beim Beenden des Browsers
> gelöscht werden. Dann gibt es zwar noch (bis zum Timeout) die
> Server-Session, aber keine Möglichkeit mehr, darauf zuzugreifen. Also alles
> im grünen Bereich, oder?


Vielleicht möchte der Server die Session dennoch zeitnah loswerden, um
z.B. anderen Nutzern Zugriff zu gewähren. Wordpress und Confluence
machen sowas. Confluence arbeitet offenbar mit 30s-Pings.

Stefan
Thomas 'PointedEars' Lahn (07.12.2018, 21:22)
Stefan Reuther wrote:
> Am 06.12.2018 um 21:22 schrieb Thomas 'PointedEars' Lahn:
> Vielleicht möchte der Server die Session dennoch zeitnah loswerden, um
> z.B. anderen Nutzern Zugriff zu gewähren.


Dieses Problem löst man nicht so, sondern mit weiteren User-Accounts. Dann
ist auch klar, wer der Benutzer ist.

> Wordpress und Confluence machen sowas. Confluence arbeitet offenbar mit 30s-Pings.


Nur weil einige oder sogar viele etwas tun, macht es das noch lange nicht
richtig.
Arno Welzel (07.12.2018, 22:09)
Thomas 'PointedEars' Lahn:

[...]
> *Alle* Bookmarks mit URI-Präfix “
> *löschen* und ersetzen durch die äquivalenten mit Präfix
> <https://developer.mozilla.org/>.
> JETZT. SOFORT.
> <https://www.w3fools.com/>


Zitat:

When W3Fools was launched in 2011, the state of documentation for
developers was poor. This site documented many content errors and issues
with the W3Schools website. The Mozilla Developer Network was around but
it did not have much support at the time.

Today, W3Schools has largely resolved these issues and addressed the
majority of the undersigned developers' concerns. For many beginners,
W3Schools has structured tutorials and playgrounds that offer a decent
learning experience. Do keep in mind: a more complete education will
certainly include MDN and other reputable resources.

(Zitat Ende)
Arno Welzel (07.12.2018, 22:13)
Ralph Stahl:

> Ich möchte erreichen, dass beim Schließen eines Browserfensters über das
> Kreuzchen rechts oben als letzte Amtshandlung die im Browser laufende
> Anwendung noch ordentlich geschlossen wird (Session schließen etc). Nach


Gehe davon aus, dass das nicht geht. Denn wenn sowas zuverlässig möglich
wäre, könnte jede Website beim Beenden des Browsers noch beliebig
umfangreiche Aktionen auslösen, auf die der Browser dann auch warten muss.

Eine Anwendung *muss* damit klarkommen, dass der Browser einfach beendet
wird oder man die Netzwerkverbindung trennt. Die übliche Lösung ist es,
Sessions mit einem Timeout zu versehen und nach einer bestimmten Zeit
ohne eingehende Anfragen durch den Browser einfach aufzuräumen.
Arno Welzel (07.12.2018, 22:17)
Thomas 'PointedEars' Lahn:

> Stefan Reuther wrote:
> Dieses Problem löst man nicht so, sondern mit weiteren User-Accounts. Dann
> ist auch klar, wer der Benutzer ist.


Szenario:

User A öffnet ein Dokument zur Bearbeitung, wofür es exklusiv gesperrt
wird, und der Browser wird beendet, ohne dass die Bearbeitung beendet wurde.

Ohne kurzes Timeout würde diese Sperre u.U. sehr lange bestehen bleiben.
Sessions mit nur für 30 Sekunden Gültigkeit zu haben, will man aber auch
nicht, weil ein Nutzer durchaus mal mehr als 30 Sekunden braucht, um die
Bearbeitung eines Dokuments zu beenden.

>> Wordpress und Confluence machen sowas. Confluence arbeitet offenbar mit 30s-Pings.

> Nur weil einige oder sogar viele etwas tun, macht es das noch lange nicht
> richtig.


Was wäre denn die "richtige" Lösung?
Jan Novak (10.12.2018, 11:02)
Am 07.12.18 um 20:22 schrieb Thomas 'PointedEars' Lahn:
> Stefan Reuther wrote:
> Dieses Problem löst man nicht so, sondern mit weiteren User-Accounts. Dann
> ist auch klar, wer der Benutzer ist.
> Nur weil einige oder sogar viele etwas tun, macht es das noch lange nicht
> richtig.


Es ist aber nicht "Falsch", nur weil "Du" es nicht für richtig hälst.

Jan
Ralph Stahl (10.12.2018, 11:46)
Arno Welzel schrieb:
> Ralph Stahl:
> Gehe davon aus, dass das nicht geht. Denn wenn sowas zuverlässig möglich
> wäre, könnte jede Website beim Beenden des Browsers noch beliebig
> umfangreiche Aktionen auslösen, auf die der Browser dann auch warten muss.
> Eine Anwendung *muss* damit klarkommen, dass der Browser einfach beendet
> wird oder man die Netzwerkverbindung trennt. Die übliche Lösung ist es,
> Sessions mit einem Timeout zu versehen und nach einer bestimmten Zeit
> ohne eingehende Anfragen durch den Browser einfach aufzuräumen.


Schon klar, Arno. Die Gesamtanwendung ist noch in der Entwicklung und
vermutlich wird es ohne solche Kunststücke gehen. Aber die Anforderung
des Kunden ist eben, dass es eine Möglichkeit geben sollte, bei der
Aktion "Schließen" irgendwas mehr oder weniger Gescheites tun zu können.
Die Session ist dabei nur eine Möglichkeit. Und es ist keine Anwendung
für die Öffentlichkeit, wo man alles mögliche erwarten müsste. Aber ja,
ein "Hausfrauentest" der Art "klicke doch einfach mal blöd hier rum"
sollte nicht zum Verlust führen.

Ich danke allen. Einige gelesene Aspekte werden mir sicher nützen :-).

Ralph
Thomas 'PointedEars' Lahn (10.12.2018, 22:26)
Jan Novak wrote:
> Am 07.12.18 um 20:22 schrieb Thomas 'PointedEars' Lahn:
>> Stefan Reuther wrote:
>>> Wordpress und Confluence machen sowas. Confluence arbeitet offenbar mit 30s-Pings.

>> Nur weil einige oder sogar viele etwas tun, macht es das noch lange nicht
>> richtig.

> Es ist aber nicht "Falsch", nur weil "Du" es nicht für richtig hälst.


Nuhr!

F’up2 zu Dir nach Hause°

Ähnliche Themen