Server-sendte begivenheder i foråret

1. Oversigt

I denne tutorial ser vi, hvordan vi kan implementere Server-Sent-Events-baserede API'er med Spring.

Kort sagt, Server-Sent-Events, eller SSE for kort, er en HTTP-standard, der gør det muligt for en webapplikation at håndtere en ensrettet begivenhedsstrøm og modtage opdateringer, når serveren udsender data.

Spring 4.2-versionen understøttede det allerede, men startende med Spring 5 har vi nu en mere idiomatisk og praktisk måde at håndtere det på.

2. SSE med Spring 5 Webflux

For at opnå dette, vi kan gøre brug af implementeringer som f.eks Strøm klasse leveret af Reaktor bibliotek eller potentielt ServerSentEvent enhed, som giver os kontrol over begivenhedens metadata.

2.1. Stream begivenheder ved hjælp af Strøm

Strøm er en reaktiv repræsentation af en strøm af begivenheder - den håndteres forskelligt baseret på den angivne anmodning eller svarmedietype.

For at oprette et SSE-streaming-slutpunkt bliver vi nødt til at følge W3C-specifikationerne og angive dens MIME-type som tekst / event-stream:

@GetMapping (sti = "/ stream-flux", producerer = MediaType.TEXT_EVENT_STREAM_VALUE) offentlig Flux streamFlux () {return Flux.interval (Duration.ofSeconds (1)) .map (sekvens -> "Flux -" + LocalTime.now () .toString ()); }

Det interval metode skaber en Strøm der udsender lang værdier trinvist. Derefter kortlægger vi disse værdier til vores ønskede output.

Lad os starte vores applikation og prøve den ved at gennemse slutpunktet derefter.

Vi ser, hvordan browseren reagerer på de begivenheder, der skubbes sekund for sekund af serveren. For mere information om Strøm og Reaktorkerne, vi kan tjekke dette indlæg.

2.2. Brug af ServerSentEvent Element

Vi indpakker nu vores output Snor ind i en ServerSentSevent gøre indsigelse og undersøge fordelene ved at gøre dette:

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

Som vi kan forstå, der er et par fordele ved at bruge ServerSentEvent enhed:

  1. vi kan håndtere begivenhedsmetadataene, som vi har brug for i et reelt tilfælde
  2. vi kan ignorere “tekst / event-stream”Mediatypedeklaration

I dette tilfælde specificerede vi en id, en begivenhedsnavnog vigtigst af alt det faktiske data af begivenheden.

Vi kunne også have tilføjet en kommentarer attribut, og en prøve igen værdi, som angiver den genforbindelse, der skal bruges, når man prøver at sende begivenheden.

2.3. Forbruger server-sendte begivenheder med en WebClient

Lad os nu forbruge vores begivenhedsstrøm med en Webklient.:

offentlig ugyldighed consumeServerSentEvent () {WebClient-klient = WebClient.create ("// localhost: 8080 / sse-server"); ParameterizedTypeReference type = ny ParameterizedTypeReference() {}; Strøm eventStream = client.get () .uri ("/ stream-sse") .hent () .bodyToFlux (type); eventStream.subscribe (content -> logger.info ("Time: {} - event: name [{}], id [{}], content [{}]", LocalTime.now (), content.event (), content.id (), content.data ()), fejl -> logger.error ("Fejl ved modtagelse af SSE: {}", fejl), () -> logger.info ("Fuldført !!!")); }

Det abonnere metode giver os mulighed for at angive, hvordan vi fortsætter, når vi modtager en begivenhed med succes, når der opstår en fejl, og når streaming er afsluttet.

I vores eksempel brugte vi hente metode, som er en enkel og ligetil måde at få responsorganet på.

Denne metode kaster automatisk en WebClientResponseException hvis vi modtager et 4xx- eller 5xx-svar, medmindre vi håndterer scenarierne ved at tilføje et onStatus udmelding.

På den anden side kunne vi have brugt udveksling metode, som også giver adgang til ClientResponse og signalerer heller ikke fejl ved svigtende svar.

Vi er nødt til at tage i betragtning, at vi kan omgå ServerSentEvent indpakning, hvis vi ikke har brug for begivenhedsmetadataene.

3. SSE-streaming i foråret MVC

Som vi sagde, blev SSE-specifikationen understøttet siden foråret 4.2, hvor SseEmitter klasse blev introduceret.

Kort sagt definerer vi en ExecutorService, en tråd hvor SseEmitter vil gøre sit arbejde med at skubbe data og returnere emitterinstansen og holde forbindelsen åben på denne måde:

@GetMapping ("/ stream-sse-mvc") offentlig SseEmitter streamSseMvc () {SseEmitter emitter = ny SseEmitter (); ExecutorService sseMvcExecutor = Executors.newSingleThreadExecutor (); sseMvcExecutor.execute (() -> {prøv {for (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); }}); returner emitter; }

Sørg altid for at vælge det rigtige ExecutorService til dit brugsscenarie.

Vi kan lære mere om SSE i Spring MVC og se på andre eksempler ved at læse denne interessante vejledning.

4. Forståelse af serversendede begivenheder

Nu hvor vi ved, hvordan vi implementerer SSE-slutpunkter, lad os prøve at gå lidt dybere ved at forstå nogle underliggende begreber.

En SSE er en specifikation, der er vedtaget af de fleste browsere for at tillade streaming af begivenheder envejs når som helst.

'Begivenhederne' er kun en strøm af UTF-8-kodede tekstdata, der følger det format, der er defineret af specifikationen.

Dette format består af en række nøgleværdielementer (id, prøv igen, data og begivenhed, som angiver navnet) adskilt af linjeskift.

Kommentarer understøttes også.

Specifikationen begrænser ikke dataets nyttelastformat på nogen måde; vi kan bruge et simpelt Snor eller en mere kompleks JSON- eller XML-struktur.

Et sidste punkt, vi skal tage i betragtning, er forskellen mellem at bruge SSE-streaming og WebSockets.

Mens WebSockets tilbyde fuld duplex (tovejs) kommunikation mellem serveren og klienten, mens SSE bruger envejs kommunikation.

Også, WebSockets er ikke en HTTP-protokol, og i modsætning til SSE tilbyder den ikke standarder til fejlhåndtering.

5. Konklusion

For at opsummere har vi i denne artikel lært de vigtigste begreber ved SSE-streaming, hvilket utvivlsomt er en stor ressource, der giver os mulighed for at oprette næste generations systemer.

Vi er nu i en fremragende position til at forstå, hvad der sker under emhætten, når vi bruger denne protokol.

Desuden supplerede vi teorien med nogle enkle eksempler, som kan findes i vores Github-arkiv.


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