2015-12-30 4 views
5

Ich benutze serverseitige Ereignisse (SSE) in Java Spring. Jedes Mal, wenn ein neuer Client abonniert das Ereignis Service, den ich den folgenden Code an dem REST-Controller ausführen:Java Frühling SseEmitter/ResponseBodyEmitter: Ermitteln Browser neu geladen

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

Dann, wenn ein Ereignis an den Kunden mitgeteilt werden muß ich ausführen:

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

Das Problem Wenn einer der Clients den Browser neu lädt, wird der Emitter nicht (wie erwartet) abgeschlossen, und beim Aufruf des obigen Codes erhalte ich eine Ausnahme für unterbrochene Pipes. Erst nachdem diese Ausnahme ausgelöst wurde, sehe ich, dass der Emitter abgeschlossen ist.

Gibt es eine Möglichkeit, dieses Problem zu lösen?

Antwort

2

Wenn der Browser neu lädt, wird es eine neue EventSource zu Ihrem Server einrichten, richtig? Ihr Problem ist mit dem alten, das keinen Client-Endpunkt mehr hat.

Ich schlage vor, Sie versuchen zu erkennen, dass es die gleiche Client-Verbindung ist, und dann explizit auf dem alten Emitter aufrufen.

In meinem Fall kann ich dies anhand eines Tokens erkennen, das von der EventSource als URL-Parameter übergeben wird. Wenn ich den neu erstellten Emitter an ein "Benutzerobjekt" anschließe, vergewissere ich mich, dass ich den vorherigen Emitter abgeschlossen habe, bevor ich das Neue der Benutzerfeldvariablen zugewiesen habe.

Aus Ihrem Code scheint es, dass Sie eine Liste oder einen Satz von Emittern haben. Können Sie vielleicht stattdessen eine Karte erstellen, in der Sie eine Client-Identität als Schlüssel und den Emitter als Wert haben?

Ich kann Ihnen nicht genau sagen, welche Information als Client-Identität zu verwenden ist, da alles von Ihrer Anwendung abhängt. In meinem Fall ist es ein JWT-Token, aber Sie könnten vielleicht einfach ein Client-Nummerierungsschema erstellen ...

+0

Wie behandeln Sie mehrere Registerkarten, die JWT wird für alle Registerkarten in der Sitzung gleich sein, richtig? – TruckDriver

+0

Was ist, wenn der Client die App abrupt schließt, nie wieder für 30 Tage, die alte Verbindung bleibt noch offen? Dies funktioniert auch nicht gut, wenn mehrere App-Server loadbalanced sind - da sich der Benutzer beim erneuten Verbinden mit einem anderen AS verbinden kann. Dies scheint kein vielversprechender Ansatz zu sein. – user1102532

+0

Nein, der SseEmitter wird mit einem Zeitüberschreitungswert im Konstruktor erstellt. Die Zeitüberschreitung bezieht sich nicht auf Leerlauf, sondern eher auf "Time-to-Live". Durch den Entwurf werden die Verbindungen alle z. X Sekunden/Minuten, und der Client wird es neu erstellen ... wenn es noch benötigt wird. Beim Lastenausgleich muss der Servercode natürlich nicht auf den Status im Arbeitsspeicher angewiesen sein, um die Sitzung des Clients neu zu erstellen, wenn der Client eine Verbindung herstellt oder die Verbindung wieder herstellt. Aber noch einmal, das Design des SSE und auch des Spring SseEmitter ist inhärent sitzungs-/verbindungsorientiert, so lange die Verbindung besteht, können Sie in mem arbeiten. –

Verwandte Themen