web-dev-qa-db-fra.com

Comment maintenir une connexion WebSockets entre les pages?

Sur l'un de mes scripts, j'ai ce code:

var webSocket = window.WebSocket || window.MozWebSocket;
window.ws = new webSocket('ws://64.121.210.140:2585/consoleappsample', 'my-protocol');

Ce qui fonctionne bien. Cependant, lorsque l'utilisateur change de page, je dois rétablir la connexion. Je crois que cela cause des problèmes dans mon code car si le client envoie des données au serveur puis change de page, les données peuvent ne pas être reçues et des conditions de concurrence critique se produisent.

J'ai essayé de mettre le window.ws de portée mondiale, mais cela ne semble pas résoudre le problème. Existe-t-il un moyen pour la connexion WebSockets de persister entre les pages afin que la connexion n'ait pas besoin d'être constamment rétablie?

30
Ryan Peschel

La portée globale que vous avez mentionnée est toujours liée au contexte JavaScript, et un contexte est créé pour chaque fenêtre (et détruit lorsque le document est déchargé de la mémoire). Par conséquent, vos efforts sont inutiles: vous ne pouvez pas garder une connexion ouverte si l'utilisateur change de page. Bien sûr, vous pouvez avoir votre application Web en tant qu'application "page unique", où toutes les données sont chargées à l'aide de XMLHttpRequest/ajax/WebSocket. Donc, quitter la page signifie quitter/arrêter l'application, et il est logique de fermer le socket.

Une autre vieille approche pourrait être de placer vos pages dans un cadre, où l'utilisateur ne navigue que dans le cadre (même si cela prend toute la taille de la fenêtre). De cette façon, vous pouvez créer votre WebSocket dans la fenêtre la plus haute, qui n'est jamais modifiée (cela signifie également que l'URL affichée dans la barre d'emplacement sera toujours la même).

Cela dit, je suis d'accord avec @dystroy: votre application devrait toujours être capable de gérer ce scénario - l'utilisateur pourrait avoir un problème de réseau et perdre la connexion pendant un moment, même s'il ne quitte pas la page.

24
ZER0

Vous pouvez essayer de créer votre connexion WebSocket dans un WebWorker partagé qui permet à plusieurs pages du même domaine de partager un contexte d'exécution. Cependant, il n'est pas clair si les travailleurs partagés persistent pendant un rechargement de page ou remplacent: les travailleurs Web partagés persistent-ils pendant un rechargement de page unique, navigation dans les liens

De plus, les WebWorkers partagés ont support limité du navigateur (webkit et Opera) actuellement.

Mise à jour :

Étant donné qu'un seul travailleur Web partagé peut servir plusieurs pages, l'implémentation est légèrement plus compliquée que les travailleurs Web normaux.

Voici un exemple de travailleur Web partagé qui utilise WebSockets et peut partager entre

D'abord le HTML:

<!DOCTYPE html>
<html>
<body>
<script>
    var worker = new SharedWorker("shared.js");
    worker.port.addEventListener("message", function(e) {
        console.log("Got message: " + e.data);
    }, false);
    worker.port.start();
    worker.port.postMessage("start");
</script>
</body>
</html>

Le Javascript qui implémente le travailleur partagé dans shared.js:

var ws = null
var url = "ws://" + location.hostname + ":6080"
self.addEventListener("connect", function(e) {
    var port = e.ports[0]
    port.addEventListener("message", function(e) {
        if (e.data === "start") {
            if (ws === null) {
                ws = new WebSocket(url);
                port.postMessage("started connection to " + url);
            } else {
                port.postMessage("reusing connection to " + url);
            }
        }
    }, false);
    port.start();
}, false);

J'ai vérifié que cela fonctionne dans Chrome 52.

19
kanaka

Malheureusement, la solution la plus propre sans changer votre site dans une application SPA est obtenue en utilisant un seul ServiceWorker car il fait le travail en arrière-plan (également avec l'onglet fermé) et résout également les problèmes de plusieurs onglets. J'ai dit "malheureusement" car ils ne sont toujours pas compatibles avec la plupart des navigateurs. La seule solution que j'ai trouvée par moi-même consiste à regrouper les canaux de socket côté serveur et à créer une file d'attente afin de conserver les messages perdus en changeant de page. Dans ce cas, vous avez une sorte de canaux virtuels.

1
Marcello Kad