Door de server verzonden gebeurtenissen in het voorjaar

1. Overzicht

In deze tutorial zullen we zien hoe we Server-Sent-Events-gebaseerde API's kunnen implementeren met Spring.

Simpel gezegd, Server-Sent-Events, of kortweg SSE, is een HTTP-standaard waarmee een webtoepassing een unidirectionele gebeurtenisstroom kan afhandelen en updates kan ontvangen wanneer de server gegevens uitzendt.

Spring 4.2-versie ondersteunde het al, maar vanaf Spring 5 hebben we nu een meer idiomatische en gemakkelijkere manier om ermee om te gaan.

2. SSE met Spring 5 Webflux

Om dit te behalen, we kunnen gebruik maken van implementaties zoals de Flux klasse geboden door de Reactor bibliotheek, of mogelijk de ServerSentEvent entiteit, wat ons controle geeft over de metadata van de gebeurtenissen.

2.1. Stream evenementen met Flux

Flux is een reactieve weergave van een stroom gebeurtenissen - deze wordt anders afgehandeld op basis van het gespecificeerde verzoek- of antwoordmediatype.

Om een ​​SSE-streaming-eindpunt te maken, moeten we de W3C-specificaties volgen en het MIME-type aanwijzen als tekst / event-stream:

@GetMapping (path = "/ stream-flux", produceert = MediaType.TEXT_EVENT_STREAM_VALUE) openbare Flux streamFlux () {return Flux.interval (Duration.ofSeconds (1)) .map (sequentie -> "Flux -" + LocalTime.now () .toString ()); }

De interval methode creëert een Flux dat uitstraalt lang waarden incrementeel. Vervolgens brengen we die waarden in kaart naar onze gewenste output.

Laten we onze applicatie starten en het uitproberen door vervolgens door het eindpunt te bladeren.

We zullen zien hoe de browser reageert op de gebeurtenissen die seconde voor seconde door de server worden gepusht. Voor meer informatie over Flux en de Reactorkern, kunnen we dit bericht bekijken.

2.2. Gebruikmakend van de ServerSentEvent Element

We zullen nu onze uitvoer verpakken Draad in een ServerSentSevent bezwaar maken en de voordelen onderzoeken om dit te doen:

@GetMapping ("/ stream-sse") openbare Flux streamEvents () {return Flux.interval (Duration.ofSeconds (1)) .map (reeks -> ServerSentEvent. builder () .id (String.valueOf (reeks)) .event ("periodic-event") .data (" SSE - "+ LocalTime.now (). ToString ()) .build ()); }

Zoals we kunnen waarderen, er zijn een aantal voordelen van het gebruik van de ServerSentEvent entiteit:

  1. we kunnen omgaan met de metadata van de gebeurtenissen, die we nodig zouden hebben in een real-case scenario
  2. we kunnen negeren "tekst / event-stream”Mediatype verklaring

In dit geval hebben we een ID kaart, een evenement naam, en, belangrijker nog, de feitelijke gegevens van het evenement.

We hadden ook een opmerkingen attribuut, en een probeer het opnieuw waarde, die de herverbindingstijd specificeert die moet worden gebruikt bij het verzenden van de gebeurtenis.

2.3. De door de server verzonden gebeurtenissen gebruiken met een webclient

Laten we nu onze evenementstream bekijken met een Web cliënt.:

public void consumeServerSentEvent () {WebClient client = WebClient.create ("// localhost: 8080 / sse-server"); ParameterizedTypeReference type = new ParameterizedTypeReference() {}; Flux eventStream = client.get () .uri ("/ stream-sse") .retrieve () .bodyToFlux (type); eventStream.subscribe (content -> logger.info ("Tijd: {} - event: naam [{}], id [{}], content [{}]", LocalTime.now (), content.event (), content.id (), content.data ()), error -> logger.error ("Fout bij het ontvangen van SSE: {}", fout), () -> logger.info ("Voltooid !!!")); }

De abonneren Met deze methode kunnen we aangeven hoe we verder gaan als we een evenement met succes ontvangen, als er een fout optreedt en als het streamen is voltooid.

In ons voorbeeld hebben we de ophalen methode, wat een eenvoudige en ongecompliceerde manier is om de responsbody te krijgen.

Deze methode gooit automatisch een WebClientResponseException als we een 4xx- of 5xx-antwoord ontvangen, tenzij we de scenario's afhandelen door een onStatus uitspraak.

Aan de andere kant hadden we de uitwisseling methode ook, die toegang geeft tot de ClientResponse en geeft ook geen foutsignaal bij falende reacties.

We moeten er rekening mee houden dat we het ServerSentEvent wrapper als we de metadata van de gebeurtenis niet nodig hebben.

3. SSE-streaming in Spring MVC

Zoals we al zeiden, werd de SSE-specificatie ondersteund sinds Spring 4.2, toen het SseEmitter klasse werd geïntroduceerd.

In eenvoudige bewoordingen definiëren we een ExecutorService, een draad waar de SseEmitter zal zijn werk doen door gegevens te pushen en de emitterinstantie terug te sturen, waarbij de verbinding op deze manier open blijft:

@GetMapping ("/ stream-sse-mvc") openbare SseEmitter streamSseMvc () {SseEmitter emitter = nieuwe SseEmitter (); ExecutorService sseMvcExecutor = Executors.newSingleThreadExecutor (); sseMvcExecutor.execute (() -> {probeer {voor (int i = 0; true; i ++) {SseEventBuilder event = SseEmitter.event () .data ("SSE MVC -" + LocalTime.now (). toString ()) .id (String.valueOf (i)) .name ("sse event - mvc"); emitter.send (event); Thread.sleep (1000);}} catch (Exception ex) {emitter.completeWithError (ex); }}); retourzender; }

Zorg er altijd voor dat u de goede kiest ExecutorService voor uw use-case scenario.

We kunnen meer leren over SSE in Spring MVC en andere voorbeelden bekijken door deze interessante tutorial te lezen.

4. Inzicht in door de server verzonden gebeurtenissen

Nu we weten hoe we SSE-eindpunten moeten implementeren, gaan we proberen wat dieper te gaan door enkele onderliggende concepten te begrijpen.

Een SSE is een specificatie die door de meeste browsers wordt gebruikt om gebeurtenissen op elk moment unidirectioneel te kunnen streamen.

De ‘events’ zijn slechts een stroom UTF-8-gecodeerde tekstgegevens die het formaat volgen dat is gedefinieerd door de specificatie.

Dit formaat bestaat uit een reeks sleutelwaarde-elementen (id, retry, data en event, wat de naam aangeeft) gescheiden door regeleinden.

Opmerkingen worden ook ondersteund.

De specificatie beperkt het formaat van de gegevenspayload op geen enkele manier; we kunnen een simpele gebruiken Draad of een meer complexe JSON- of XML-structuur.

Een laatste punt waarmee we rekening moeten houden, is het verschil tussen het gebruik van SSE-streaming en WebSockets.

Terwijl WebSockets bieden full-duplex (bidirectionele) communicatie tussen de server en de client, terwijl SSE uni-directionele communicatie gebruikt.

Ook, WebSockets is geen HTTP-protocol en biedt, in tegenstelling tot SSE, geen standaarden voor foutafhandeling.

5. Conclusie

Samenvattend: in dit artikel hebben we de belangrijkste concepten van SSE-streaming geleerd, wat ongetwijfeld een geweldige bron is waarmee we systemen van de volgende generatie kunnen maken.

We bevinden ons nu in een uitstekende positie om te begrijpen wat er onder de motorkap gebeurt wanneer we dit protocol gebruiken.

Verder hebben we de theorie aangevuld met enkele eenvoudige voorbeelden, die te vinden zijn in onze Github-repository.


$config[zx-auto] not found$config[zx-overlay] not found