Server-Sent Events vs. WebFlux
- Mark Kendall
- Mar 9
- 3 min read
Server-Sent Events vs. WebFlux: An Example
This article demonstrates the implementation of Server-Sent Events (SSE) using both a client-side TypeScript service and a server-side Spring WebFlux REST API, providing a practical comparison between these technologies.
Introduction
Server-Sent Events (SSE) and WebFlux are technologies used for real-time data streaming in web applications. SSE is a unidirectional communication protocol that allows a server to push data to a client over a single, long-lived HTTP connection. WebFlux, part of Spring Web 5, is a reactive programming model designed for building asynchronous, non-blocking web applications.
Client-Side Implementation (TypeScript)
We'll create an SseService class in TypeScript to handle the client-side SSE connection.
TypeScript
// sse-service.ts
import { Flux, interval, map } from 'rxjs';
class SseService {
private eventSource: EventSource | null = null;
constructor(private url: string) {}
connect(onMessage: (data: string) => void, onError: (error: Event) => void) {
this.eventSource = new EventSource(this.url);
this.eventSource.onmessage = (event) => {
onMessage(event.data);
};
this.eventSource.onerror = (error) => {
onError(error);
};
}
disconnect() {
if (this.eventSource) {
this.eventSource.close();
this.eventSource = null;
}
}
static createWebFluxStream(intervalMs: number): Flux<string> {
return interval(intervalMs).pipe(
map((sequence) => `data: Event ${sequence}\n\n`)
);
}
}
export default SseService;
This class encapsulates the SSE connection logic. The connect method establishes the connection and sets up event listeners. The disconnect method closes the connection. The createWebFluxStream static method emulates a reactive stream using RxJS, useful for testing or server-side TypeScript implementations.
React Component (App.tsx)
We'll create a simple React component that uses the SseService to display received events.
TypeScript
// App.tsx
import React, { useState, useEffect } from 'react';
import SseService from './sse-service';
function App() {
const [messages, setMessages] = useState<string[]>([]);
const sseService = new SseService('/events');
useEffect(() => {
const handleMessage = (data: string) => {
setMessages((prevMessages) => [...prevMessages, data]);
};
const handleError = (error: Event) => {
console.error('SSE error:', error);
};
sseService.connect(handleMessage, handleError);
return () => {
sseService.disconnect();
};
}, []);
return (
<div>
<h1>Server-Sent Events</h1>
<ul>
{messages.map((message, index) => (
<li key={index}>{message}</li>
))}
</ul>
</div>
);
}
export default App;
This component initializes the SseService, connects to the /events endpoint, and displays the received messages in a list.
Server-Side Implementation (Spring WebFlux)
We'll create a Spring WebFlux REST API endpoint that serves SSE events.
Java
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;
import java.time.Duration;
@RestController
public class SseController {
@GetMapping(value = "/events", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<String> events() {
return Flux.interval(Duration.ofSeconds(1))
.map(sequence -> "data: " + "Event " + sequence + "\n\n");
}
}
This controller defines a /events endpoint that returns a Flux<String> representing the SSE stream. The Flux.interval operator emits a sequence of numbers at a specified interval, and the map operator transforms them into SSE-formatted strings.
Key Differences and Considerations
Directionality: SSE is unidirectional (server to client), while WebFlux supports bidirectional communication.
Complexity: SSE is simpler to implement for server-to-client updates, while WebFlux offers more advanced features for complex asynchronous scenarios.
Use Cases: SSE is ideal for real-time notifications and live feeds, while WebFlux is suitable for building highly concurrent and scalable web applications.
Error Handling: In both the client and server, proper error handling is essential to ensure the robustness of the SSE connection.
Disconnection Handling: Server-side logic should be designed to handle client disconnections gracefully, especially when dealing with database updates or other critical operations.
Webflux Usage: Webflux is a great framework to implement SSE, and is not a competing technology.
Running the Example
Server: Run the Spring Boot application.
Client: Run the React application.
Open the React application in a web browser. You should see the received events displayed in the list.
This example provides a clear understanding of how to implement SSE using TypeScript and Spring WebFlux, highlighting the key differences and considerations between these technologies.
Comments