Server-sendte hendelser om våren

1. Oversikt

I denne opplæringen vil vi se hvordan vi kan implementere Server-Sent-Events-baserte APIer med Spring.

Enkelt sagt, Server-Sent-Events, eller forkortet SSE, er en HTTP-standard som gjør at et webapplikasjon kan håndtere en ensrettet hendelsesstrøm og motta oppdateringer når serveren sender ut data.

Spring 4.2-versjonen støttet den allerede, men fra og med Spring 5 har vi nå en mer idiomatisk og praktisk måte å håndtere den på.

2. SSE med Spring 5 Webflux

For å oppnå dette, vi kan bruke implementeringer som Flux klasse levert av Reaktor biblioteket, eller potensielt ServerSentEvent enhet, som gir oss kontroll over hendelsesmetadataene.

2.1. Stream hendelser ved hjelp Flux

Flux er en reaktiv representasjon av en strøm av hendelser - den håndteres forskjellig basert på den angitte forespørselen eller responsmedietypen.

For å opprette et SSE-endepunkt for streaming, må vi følge W3C-spesifikasjonene og angi MIME-typen som tekst / event-stream:

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

De intervall metoden skaper en Flux som avgir lang verdier trinnvis. Deretter kartlegger vi disse verdiene til ønsket produksjon.

La oss starte applikasjonen vår og prøve den ved å bla gjennom sluttpunktet da.

Vi får se hvordan nettleseren reagerer på hendelsene som blir presset sekund for sekund av serveren. For mer informasjon om Flux og Reaktorkjerne, kan vi sjekke ut dette innlegget.

2.2. Gjør bruk av ServerSentEvent Element

Vi skal nå pakke ut produksjonen vår String inn i en ServerSentSevent protesterer og undersøker fordelene ved å gjøre dette:

@GetMapping ("/ stream-sse") offentlig strøm 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 sette pris på, det er et par fordeler med å bruke ServerSentEvent enhet:

  1. vi kan håndtere hendelsesmetadataene, som vi trenger i et reelt tilfelle
  2. vi kan ignorere “tekst / event-stream”Mediatypedeklarasjon

I dette tilfellet spesifiserte vi en id, en arrangementsnavn, og viktigst, det faktiske data av arrangementet.

Vi kunne også ha lagt til en kommentarer attributt, og en prøv på nytt verdi, som vil spesifisere gjenkoblingstiden som skal brukes når du prøver å sende hendelsen.

2.3. Forbruker server sendte hendelser med en WebClient

La oss nå konsumere arrangementstrømmen vår med en WebClient.:

offentlig tomrom consumeServerSentEvent () {WebClient client = WebClient.create ("// localhost: 8080 / sse-server"); ParameterizedTypeReference type = ny ParameterizedTypeReference() {}; Flux 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 ()), feil -> logger.error ("Feil ved mottak av SSE: {}", feil), () -> logger.info ("Fullført !!!")); }

De abonnere metoden lar oss indikere hvordan vi skal fortsette når vi mottar en hendelse vellykket, når en feil oppstår og når streaming er fullført.

I vårt eksempel brukte vi hente metode, som er en enkel og grei måte å få responsorganet på.

Denne metoden kaster automatisk en WebClientResponseException hvis vi mottar et 4xx- eller 5xx-svar med mindre vi håndterer scenariene og legger til et onStatus uttalelse.

På den annen side kunne vi ha brukt Utveksling metoden også, som gir tilgang til ClientResponse og signaliserer heller ikke på sviktende svar.

Vi må ta hensyn til at vi kan omgå ServerSentEvent wrapper hvis vi ikke trenger hendelsesmetadata.

3. SSE-streaming i vår-MVC

Som vi sa ble SSE-spesifikasjonen støttet siden våren 4.2, da SseEmitter klasse ble introdusert.

Enkelt sagt vil vi definere en ExecutorService, en tråd der SseEmitter vil gjøre sitt arbeid med å skyve data, og returnere emitterforekomsten og holde forbindelsen åpen på denne måten:

@GetMapping ("/ stream-sse-mvc") public SseEmitter streamSseMvc () {SseEmitter emitter = new SseEmitter (); ExecutorService sseMvcExecutor = Executors.newSingleThreadExecutor (); sseMvcExecutor.execute (() -> {try {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); }}); returemitter; }

Sørg alltid for å velge riktig ExecutorService for ditt bruksscenario.

Vi kan lære mer om SSE i Spring MVC og se på andre eksempler ved å lese denne interessante opplæringen.

4. Forstå server-sendte hendelser

Nå som vi vet hvordan vi skal implementere SSE-endepunkter, la oss prøve å gå litt dypere ved å forstå noen underliggende konsepter.

En SSE er en spesifikasjon som er vedtatt av de fleste nettlesere for å tillate streaminghendelser ensrettet når som helst.

‘Hendelsene’ er bare en strøm av UTF-8-kodede tekstdata som følger formatet definert av spesifikasjonen.

Dette formatet består av en serie nøkkelverdielementer (id, prøv på nytt, data og hendelse, som indikerer navnet) atskilt med linjeskift.

Kommentarer støttes også.

Spesifikasjonen begrenser ikke dataets nyttelastformat på noen måte; vi kan bruke en enkel String eller en mer kompleks JSON- eller XML-struktur.

Et siste poeng vi må ta i betraktning er forskjellen mellom å bruke SSE-streaming og WebSockets.

Samtidig som WebSockets tilby full-dupleks (toveis) kommunikasjon mellom serveren og klienten, mens SSE bruker enveiskommunikasjon.

Også, WebSockets er ikke en HTTP-protokoll, og i motsetning til SSE tilbyr den ikke standarder for feilhåndtering.

5. Konklusjon

For å oppsummere, i denne artikkelen har vi lært hovedkonseptene for SSE-streaming, som utvilsomt er en flott ressurs som lar oss lage neste generasjons systemer.

Vi er nå i en utmerket posisjon til å forstå hva som skjer under panseret når vi bruker denne protokollen.

Videre komplementerte vi teorien med noen enkle eksempler, som du finner i vårt Github-arkiv.


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