Backend Development 11 min read

Server‑Sent Events (SSE) vs WebSocket vs Polling: Detailed Comparison and SpringBoot Implementation

This article explains the lightweight Server‑Sent Events (SSE) approach for one‑way server push, compares its features, connection model, performance and use cases against WebSocket and traditional polling, and provides a SpringBoot example with code snippets for building an online‑user SSE endpoint.

Top Architect
Top Architect
Top Architect
Server‑Sent Events (SSE) vs WebSocket vs Polling: Detailed Comparison and SpringBoot Implementation

In many real‑time projects the client only needs to receive messages from the server, making the full‑duplex WebSocket feature unnecessary; Server‑Sent Events (SSE) offers a simpler one‑way push solution.

Comparison Table

Feature

SSE (Server‑Sent Events)

Polling

WebSocket

Communication Direction

One‑way: server pushes to client

One‑way: client periodically requests

Two‑way: client ↔ server

Connection Type

Long‑living HTTP/1.1 or HTTP/2 connection

Short‑lived independent HTTP requests

Persistent TCP connection (WebSocket handshake)

Transport Protocol

HTTP/1.1 or HTTP/2

HTTP

TCP (via WebSocket protocol upgrade)

Browser Support

Widely supported (native HTML5)

All browsers support

Supported via WebSocket API

Message Frequency

Server can push anytime

Client decides polling interval

Real‑time bi‑directional

Server Overhead

Low – single long connection

High – new connection each poll

Higher – maintain TCP + heartbeat

Client Overhead

Low – just handle pushes

High – repeated requests

Medium – keep connection alive

Data Format

Text, JSON, etc.

Text, JSON, etc.

Any (binary, text, …)

Reconnection

Automatic on disconnect

Manual new request

Developer‑implemented

Typical Scenarios

Live data push, notifications, monitoring (one‑way)

Low‑frequency, non‑real‑time needs

Instant messaging, collaborative apps (two‑way)

Complexity

Simple, lightweight code

Simple but less performant

Complex – handshake, heart‑beat, reconnection logic

Real‑time

High – immediate server push

Low – depends on poll interval

High – bi‑directional

Firewall/Proxy Compatibility

High – standard HTTP

High – standard HTTP

May need special firewall rules for TCP

Bandwidth Consumption

Low – only data when needed

High – each poll consumes bandwidth

Low – long connection, data on demand

Why abandon WebSocket for simple push? WebSocket requires manual token handling during handshake, extra code for connection management, reconnection, and periodic message sending, which is overkill when only server‑to‑client notifications are needed.

Implementation Steps (SpringBoot)

1. Configure a custom AsyncTaskExecutor to avoid production warnings:

@Configuration
@Slf4j
public class WebMvcConfig implements WebMvcConfigurer {
    @Bean(name = "customAsyncTaskExecutor")
    public AsyncTaskExecutor customAsyncTaskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        int corePoolSize = Runtime.getRuntime().availableProcessors();
        int maxPoolSize = corePoolSize * 2;
        int queueCapacity = 500;
        executor.setCorePoolSize(corePoolSize);
        executor.setMaxPoolSize(maxPoolSize);
        executor.setQueueCapacity(queueCapacity);
        executor.setThreadNamePrefix("AsyncExecutor-");
        executor.setWaitForTasksToCompleteOnShutdown(true);
        executor.setAwaitTerminationSeconds(60);
        executor.initialize();
        return executor;
    }

    @Override
    public void configureAsyncSupport(AsyncSupportConfigurer configurer) {
        configurer.setTaskExecutor(customAsyncTaskExecutor());
        configurer.setDefaultTimeout(5000);
    }
}

2. Write the SSE endpoint that streams online user count every 5 seconds:

@PreventDuplicateSubmit
@PreAuthorize("@permission.checker('monitor:online-user:list')")
@GetMapping(value = "/user-activity-sse", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux
streamUserActivitySSE() {
    return Flux.interval(Duration.ofSeconds(5))
               .flatMap(seq -> Mono.fromCallable(onlineUserService::getUserActivityNum)
                              .onErrorReturn(0));
}

The front‑end can subscribe to /user-activity-sse and receive a continuous stream of numbers representing online users.

3. Real‑world case: a C++ ID‑card scanner required polling; using SSE would have eliminated the need for a 10‑minute quick‑and‑dirty polling implementation.

Conclusion: WebSocket, SSE, and polling each have their own strengths; choose SSE for lightweight one‑way push scenarios such as notifications, monitoring, or simple real‑time data, while WebSocket remains suitable for full bi‑directional communication.

backend developmentWebSocketSpringBootReal-time CommunicationpollingSSE
Top Architect
Written by

Top Architect

Top Architect focuses on sharing practical architecture knowledge, covering enterprise, system, website, large‑scale distributed, and high‑availability architectures, plus architecture adjustments using internet technologies. We welcome idea‑driven, sharing‑oriented architects to exchange and learn together.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.