2015-12-30 10 views
5

Utilizzo gli eventi lato server (SSE) in Java Spring. Ogni volta che un nuovo cliente sottoscrive il servizio di eventi eseguo il seguente codice al controllore REST:Sorgente Java SseEmitter/ResponseBodyEmitter: rileva il caricamento del browser

SseEmitter emitter = new SseEmitter(-1L); 
emitter.onCompletion(() -> { 
     logger.debug(TAG + "Emitter completed."); 
     emitters.remove(emitter); 
    }); 
return emitter; 

Poi, ogni volta che un evento deve essere notificato ai clienti eseguo:

for (ResponseBodyEmitter emitter: emitters) { 
     emitter.send("Message #1"); 
} 

Il problema è che quando uno dei client ricarica il browser, l'emettitore non viene completato (come mi aspettavo) e ottengo un'eccezione di pipe non corretta quando si chiama il codice sopra. Solo dopo che questa eccezione è stata attivata, vedo che l'emettitore è stato completato.

C'è un modo per risolvere questo problema?

risposta

2

Quando il browser viene ricaricato, verrà stabilita una nuova EventSource sul server, giusto? Il tuo problema è con quello vecchio, che non ha più un endpoint client.

Suggerisco di provare a rilevare che è lo stesso client che si connette e quindi chiama esplicitamente completo sul vecchio emettitore.

Nel mio caso posso rilevare questo in base a un token che passa l'EventSource come parametro URL. Quando collego l'emettitore appena creato a un "oggetto utente", mi assicuro di completare l'emettitore precedente prima di assegnare il nuovo alla variabile del campo utente.

Dal tuo codice, sembra che tu abbia una lista o una serie di emettitori. Puoi magari renderlo una mappa, dove hai l'identità del client come chiave e l'emettitore come valore?

Non posso dire esattamente quale informazione utilizzare come identità del client, poiché tutto dipende dall'applicazione. Nel mio caso è un token JWT, ma potresti semplicemente creare uno schema di numerazione client ...

+0

come stai gestendo più schede, il jwt sarà lo stesso per tutte le schede della sessione, giusto? – TruckDriver

+0

Cosa succede se il client chiude bruscamente l'app, non ritorna mai per 30 giorni, La vecchia connessione rimarrà aperta? Questo inoltre non funziona bene quando ci sono più server di applicazioni a carico bilanciato - poiché l'utente potrebbe connettersi a un AS diverso quando si riconnettono. Questo non sembra un approccio promettente. – user1102532

+0

No, SseEmitter viene creato con un valore di timeout nel costruttore. Il timeout non è relativo all'essere inattivo, ma più come un "time-to-live". In base alla progettazione, le connessioni verranno eliminate ogni e.g. X secondi/minuti e il client lo ricreerà ... se è ancora necessario. Per quanto riguarda il bilanciamento del carico, ovviamente quando il client si connette o riconnette, il codice del server non deve basarsi sullo stato in memoria per ricreare la sessione del client. Ma ancora, il design dell'SSE e anche il SseEmitter di Spring sono intrinsecamente di sessione/connessione centrica, quindi finché la connessione è attiva, puoi lavorare in mem. –

Problemi correlati