Understanding Server‑Sent Events (SSE): Concepts, Comparison with Polling/WebSocket, and Practical Demo
This article explains the use cases and implementation of Server‑Sent Events (SSE), compares it with polling and WebSocket, details its API and browser compatibility, and provides complete front‑end and Node‑Express back‑end demo code for building a real‑time push service.
In many development scenarios the server needs to push data to the client in real time, such as live dashboards, unread message notifications, or chat features.
The article introduces three common solutions for server‑to‑client data push: polling, WebSocket, and SSE.
Polling Overview
Polling is a pseudo‑push technique where the client repeatedly sends HTTP requests to the server, creating unnecessary connection overhead, consuming browser concurrency slots, and often delivering data with latency.
WebSocket Overview
WebSocket provides a full‑duplex communication channel, allowing both client and server to send messages independently. It is powerful but requires the ws/wss protocol support on both ends, making it heavier than SSE.
SSE Overview
SSE is a one‑way, long‑living HTTP/HTTPS connection that lets the server push events to the browser. It is lightweight, uses the existing HTTP infrastructure, and enjoys good browser support (except IE).
Long connections are a persistent HTTP/1.1 feature that reduces the overhead of establishing new TCP connections for each request.
SSE advantages include lower complexity, less client resource consumption, and no need for additional server configuration beyond standard HTTP headers.
Differences Between WebSocket and SSE
WebSocket is full‑duplex; SSE is server‑to‑client only.
WebSocket requires a new protocol (ws/wss); SSE works over standard HTTP.
SSE is lighter and simpler; WebSocket is more feature‑rich but heavier.
SSE automatically reconnects on disconnection; WebSocket needs extra handling.
SSE allows custom data types.
Typical scenarios: use SSE for one‑way push such as live dashboards or notification centers; use WebSocket when bidirectional communication (e.g., chat) is required.
SSE Main API
Creating an SSE connection in JavaScript:
var source = new EventSource(url);
Connection readyState values:
EventSource.CONNECTING (0) – connection not yet established or reconnecting.
EventSource.OPEN (1) – connection open and receiving data.
EventSource.CLOSED (2) – connection closed and will not reconnect.
Key events:
open – triggered when the connection is opened.
message – triggered when a message is received.
error – triggered on communication errors.
Data Format
Content-Type: text/event-stream // response format
Cache-Control: no-cache // prevent caching
Connection: keep-alive // keep the long connectionPractical Demo
The front‑end demo is a plain HTML page that creates an EventSource , checks browser support, and appends received messages to a list:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>SSE Demo</title>
</head>
<body>
<ul id="ul"></ul>
<script>
function createLi(data) {
let li = document.createElement("li");
li.innerHTML = String(data.message);
return li;
}
let source = '';
if (window.EventSource) {
source = new EventSource('http://localhost:8088/sse/');
} else {
throw new Error("当前浏览器不支持SSE");
}
source.onopen = function(event) {
console.log(source.readyState);
console.log("长连接打开");
};
source.onmessage = function(event) {
console.log(JSON.parse(event.data));
console.log("收到长连接信息");
let li = createLi(JSON.parse(event.data));
document.getElementById("ul").appendChild(li);
};
source.onerror = function(event) {
console.log(source.readyState);
console.log("长连接中断");
};
</script>
</body>
</html>The back‑end demo uses Node.js with Express to expose an /sse endpoint that sets the proper headers and sends a JSON payload every second:
const express = require('express');
const app = express();
const port = 8088;
app.all('*', (req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, X-Requested-With');
res.header('Access-Control-Allow-Methods', 'PUT,POST,GET,DELETE,OPTIONS');
res.header('Access-Control-Allow-Credentials', true);
if (req.method == 'OPTIONS') {
res.sendStatus(200);
} else {
next();
}
});
app.get('/sse', (req, res) => {
res.set({
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive'
});
console.log('进入到长连接了');
setInterval(() => {
const data = { message: `Current time is ${new Date().toLocaleTimeString()}` };
res.write(`data: ${JSON.stringify(data)}\n\n`);
}, 1000);
});
app.listen(port, () => {
console.log(`项目启动成功-http://localhost:${port}`);
});Running the two files launches a simple SSE service that streams the current time to the browser, demonstrating the lightweight nature of SSE compared to WebSocket.
Conclusion
SSE is lighter than WebSocket and works over standard HTTP.
Use SSE when only server‑to‑client push is needed (e.g., dashboards, notifications).
Choose WebSocket for bidirectional communication (e.g., chat).
Polling should be a last resort due to high resource consumption.
Note that IE does not support SSE and mini‑programs also lack SSE support.
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.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.