Acara Dihantar Pelayan pada Musim Bunga

1. Gambaran keseluruhan

Dalam tutorial ini, kita akan melihat bagaimana kita dapat menerapkan API berasaskan Server-Sent-Events dengan Spring.

Ringkasnya, Server-Sent-Events, atau SSE singkatnya, adalah standard HTTP yang membolehkan aplikasi web mengendalikan aliran acara searah dan menerima kemas kini setiap kali pelayan mengeluarkan data.

Versi Spring 4.2 sudah menyokongnya, tetapi bermula dengan Spring 5, kami sekarang mempunyai cara yang lebih idiomatik dan mudah untuk menanganinya.

2. SSE dengan Spring 5 Webflux

Untuk mencapainya, kita dapat memanfaatkan implementasi seperti kelas Flux yang disediakan oleh perpustakaan Reactor , atau berpotensi entiti ServerSentEvent , yang memberi kita kawalan terhadap metadata peristiwa.

2.1. Alirkan Acara Menggunakan Flux

Flux adalah perwakilan reaktif aliran peristiwa - ia ditangani secara berbeza berdasarkan permintaan atau jenis media respons yang ditentukan.

Untuk membuat titik akhir streaming SSE, kita harus mengikuti spesifikasi W3C dan menetapkan jenis MIME-nya sebagai aliran teks / peristiwa :

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

The selang kaedah mencipta Flux yang memancarkan panjang nilai secara berperingkat. Kemudian kami memetakan nilai-nilai tersebut ke output yang kami mahukan.

Mari mulakan aplikasi kami dan mencubanya dengan melayari titik akhir.

Kami akan melihat bagaimana penyemak imbas bertindak balas terhadap peristiwa yang didorong kedua demi dua oleh pelayan. Untuk maklumat lebih lanjut mengenai Flux dan Reactor Core , kami boleh menyemak catatan ini.

2.2. Menggunakan Elemen ServerSentEvent

Kami sekarang akan membungkus String output kami ke objek ServerSentSevent , dan meneliti faedah melakukan ini:

@GetMapping("/stream-sse") public 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()); }
    

Seperti yang dapat kita hargai, terdapat beberapa kelebihan menggunakan entiti ServerSentEvent :

  1. kita dapat menangani metadata peristiwa, yang kita perlukan dalam senario kes sebenar
  2. kita boleh mengabaikan deklarasi jenis media " teks / peristiwa-aliran "

Dalam kes ini, kami menentukan id , nama acara , dan yang paling penting, data sebenar peristiwa tersebut.

Kami juga boleh menambahkan atribut komen , dan nilai percubaan semula , yang akan menentukan masa penyambungan semula yang akan digunakan ketika cuba mengirim acara.

2.3. Menggunakan Peristiwa yang Dihantar Pelayan dengan Pelanggan Web

Sekarang mari kita gunakan aliran acara kami dengan WebClient .:

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("Time: {} - event: name[{}], id [{}], content[{}] ", LocalTime.now(), content.event(), content.id(), content.data()), error -> logger.error("Error receiving SSE: {}", error), () -> logger.info("Completed!!!")); }
      
     
    

The melanggan kaedah membolehkan kita untuk menunjukkan bagaimana kami akan diteruskan apabila kami menerima acara berjaya, apabila ralat berlaku, dan apabila live selesai.

Dalam contoh kami, kami menggunakan kaedah pengambilan , yang merupakan kaedah mudah dan mudah untuk mendapatkan badan respons.

Kaedah ini secara automatik melemparkan WebClientResponseException jika kita menerima tindak balas 4xx atau 5xx melainkan kita menangani senario yang menambahkan pernyataan onStatus .

Sebaliknya, kita juga dapat menggunakan metode pertukaran , yang menyediakan akses ke ClientResponse dan juga tidak memberi isyarat kesalahan pada respons yang gagal.

Kita harus ingat bahawa kita dapat melewati pembungkus ServerSentEvent jika kita tidak memerlukan metadata peristiwa.

3. Pengaliran SSE di Spring MVC

Seperti yang kami katakan, spesifikasi SSE didukung sejak Spring 4.2, ketika kelas SseEmitter diperkenalkan.

Dalam istilah mudah, kami akan menentukan ExecutorService , utas di mana SseEmitter akan melakukan kerja mendorong data, dan mengembalikan contoh pemancar, menjaga sambungan terbuka dengan cara ini:

@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); } }); return emitter; }

Sentiasa pastikan untuk memilih ExecutorService yang tepat untuk senario kes penggunaan anda.

Kita boleh mengetahui lebih lanjut mengenai SSE di Spring MVC dan melihat contoh lain dengan membaca tutorial menarik ini.

4. Memahami Acara Dihantar Pelayan

Sekarang setelah kita mengetahui bagaimana menerapkan titik akhir SSE, mari kita cuba mendalami dengan lebih mendalam dengan memahami beberapa konsep yang mendasari.

SSE adalah spesifikasi yang diadopsi oleh kebanyakan penyemak imbas untuk membenarkan streaming peristiwa secara tidak langsung pada bila-bila masa.

'Acara' hanyalah aliran data teks yang dikodkan UTF-8 yang mengikuti format yang ditentukan oleh spesifikasi.

Format ini terdiri daripada rangkaian elemen nilai-kunci (id, percubaan semula, data dan peristiwa, yang menunjukkan nama) yang dipisahkan oleh jeda baris.

Komen disokong juga.

Spesifikasi tidak mengehadkan format muatan data dengan cara apa pun; kita boleh menggunakan String sederhana atau struktur JSON atau XML yang lebih kompleks.

Satu perkara terakhir yang harus kita pertimbangkan adalah perbezaan antara menggunakan streaming SSE dan WebSockets .

Sementara WebSockets menawarkan komunikasi full-duplex (dua arah) antara pelayan dan klien, sementara SSE menggunakan komunikasi uni-directional.

Juga, WebSockets bukan protokol HTTP dan, bertentangan dengan SSE, ia tidak menawarkan standard pengendalian ralat.

5. Kesimpulan

Ringkasnya, dalam artikel ini kita telah mempelajari konsep utama streaming SSE, yang pastinya merupakan sumber hebat yang akan membolehkan kita membuat sistem generasi seterusnya.

Kami kini berada dalam kedudukan yang sangat baik untuk memahami apa yang sedang berlaku ketika kita menggunakan protokol ini.

Selanjutnya, kami melengkapkan teori dengan beberapa contoh mudah, yang terdapat di repositori Github kami.