2012-06-04 9 views
23

Su uno dei miei script ho questo codice:Come mantenere una connessione WebSockets tra le pagine?

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

che funziona bene. Tuttavia, quando l'utente cambia pagina, devo ristabilire la connessione. Credo che questo stia causando problemi nel mio codice perché se il client invia i dati al server e quindi modifica le pagine, i dati potrebbero non essere ricevuti e le condizioni di gara si verificano.

Ho provato a mettere lo window.ws in ambito globale ma non sembra aver risolto il problema. C'è un modo per mantenere la connessione WebSockets tra le pagine in modo che la connessione non debba essere costantemente ristabilita?

+3

Io non la penso così. Ma la logica dell'applicazione dovrebbe coprire i problemi di connessione. –

risposta

19

L'ambito globale menzionato è sempre correlato al contesto JavaScript e viene creato un contesto per ogni finestra (e distrutto quando il documento viene scaricato dalla memoria). Pertanto, i tuoi sforzi sono inutili: non puoi mantenere una connessione aperta se l'utente cambia pagina. Ovviamente puoi avere la tua webapp come applicazione "singola pagina", dove tutti i dati vengono caricati usando XMLHttpRequest/ajax/WebSocket. Quindi, lasciare la pagina significa lasciare/chiudere l'applicazione, e ha senso chiudere il socket.

Un altro vecchio approccio potrebbe essere mettere le pagine in una cornice, dove l'utente può navigare solo nel frame (anche se prende l'intera dimensione della finestra). In questo modo, puoi creare il tuo WebSocket nella finestra più in alto, che non viene mai modificata (ciò significa anche che l'URL mostrato nella barra degli indirizzi sarà sempre lo stesso).

Detto questo, ho concordato con @dystroy: la tua applicazione dovrebbe essere sempre in grado di gestire questo scenario - l'utente potrebbe avere qualche problema di rete e perdere la connessione per un momento, anche se non lascia la pagina.

+1

Con il trucco del frame, esiste un modo per far sì che la posizione nella barra degli indirizzi rifletta la posizione navigata all'interno del frame contenente il contenuto navigabile? Automaticamente? Con i collegamenti nel contenuto rimanendo semplici hrefs? – oberstet

+1

Puoi provare a fare qualcosa usando [History APIs] (https://developer.mozilla.org/en/DOM/Manipulating_the_browser_history). – ZER0

+1

So che questa è una vecchia risposta, ma se un'applicazione ha utenti che cambiano pagina, questo non martella il server socket Web con disconnessioni costanti e ricollega? – Alias

16

Si potrebbe provare a creare la connessione WebSocket in un WebWorker condiviso che consente a più pagine dello stesso dominio di condividere un contesto di esecuzione. Tuttavia, non è chiaro se i lavoratori condivisi persistono attraverso una pagina ricaricata o sostituita: Do Shared Web Workers persist across a single page reload, link navigation

Inoltre, i WebWorker condivisi hanno limited browser support (webkit e Opera) al momento.

Aggiornamento:

Dal momento che un solo lavoratore web condiviso può servire più pagine, l'implementazione è leggermente più complicato che i normali lavoratori web.

Ecco un esempio di operaio web condiviso che utilizza WebSockets e possono condividere tra

Prima il codice 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> 

Il JavaScript che implementa il lavoratore condiviso in 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); 

Ho verificato che funzioni in Chrome 52.

+0

Ho un dubbio. In tal caso, non esiste un supporto per Websocket nei webworker come possiamo mantenere il contesto dell'app. –

+0

@kongaraju, è possibile utilizzare WebSockets tramite Web Workers in Chrome e c'è un bug di Mozilla per implementare il supporto per questo in Firefox: https://bugzilla.mozilla.org/show_bug.cgi?id=504553 – kanaka

+0

Quando provo ad accedere websocket via webworkers in chrome restituisce l'eccezione DOM. puoi specificare un esempio. –

0

Purtroppo la soluzione più pulita senza modificare il sito in un'applicazione SPA si ottiene utilizzando un solo ServiceWorker perché fa il lavoro in background (anche con scheda chiusa) e risolve anche problemi di più schede. Ho detto "sfortunatamente" perché non sono ancora compatibili con la maggior parte dei browser. L'unica soluzione che ho trovato da solo consiste nel raggruppare i canali socket sul lato server e creare una coda per contenere i messaggi persi cambiando pagina. In questo caso hai una sorta di canali virtuali.

Problemi correlati