Is WebSocket Still the Best Choice for Real‑Time Push? Exploring SSE as a Lighter Alternative
The article compares polling, WebSocket, and Server‑Sent Events for server‑to‑client push, explains why polling is inefficient, outlines the advantages and browser compatibility of WebSocket and SSE, and provides step‑by‑step Node/Express and plain‑HTML demos showing how to implement SSE in practice.
Introduction
In many everyday development scenarios—such as real‑time dashboards, unread‑message notifications, or chat features—the server needs to push data to the client proactively. This article introduces Server‑Sent Events (SSE), compares it with WebSocket and traditional polling, and shows how to implement SSE with a simple Node.js/Express backend and a plain HTML frontend.
Implementation Options for Server‑to‑Client Push
Polling
WebSocket
SSE
Polling Overview
Polling creates the illusion of push by repeatedly sending HTTP requests from the client. It is considered the least desirable method because each request incurs the full HTTP handshake, consumes client resources continuously, and is limited by the browser's concurrent request cap (e.g., Chrome allows only six simultaneous connections per domain). Long‑running polls also suffer from delayed data delivery.
WebSocket Overview
WebSocket is a full‑duplex protocol (ws/wss) that enables bidirectional communication between client and server. Its strengths are powerful features and support for real‑time two‑way messaging, but it requires server‑side support for the new protocol and may have compatibility issues in older browsers.
SSE Overview
SSE is a one‑way, long‑living HTTP/1.1 connection that allows the server to push events to the browser. It is lightweight, uses the existing HTTP infrastructure, and therefore enjoys broader server support without extra configuration. However, Internet Explorer does not support SSE, and mini‑programs (e.g., WeChat) also lack support.
WebSocket vs. SSE Comparison
WebSocket: full‑duplex, stronger functionality, requires ws protocol support.
SSE: one‑way, lightweight, built on HTTP, easier to deploy.
Both provide decent browser compatibility; SSE automatically reconnects on disconnection, while WebSocket needs additional handling.
SSE supports custom data types and is less complex to implement.
SSE API Details
Creating an SSE connection in JavaScript: var source = new EventSource(url); Connection readyState values:
0 – CONNECTING (connection not yet established or disconnected)
1 – OPEN (connection established, data can be received)
2 – CLOSED (connection closed and will not reconnect)
Key SSE events:
open – triggered when the connection opens.
message – triggered when data arrives.
error – triggered on communication errors, such as disconnection.
Typical response headers for an SSE stream:
Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-aliveDemo: Frontend Code
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>SSE Demo</title>
</head>
<body>
<ul id="ul"></ul>
<script>
// Generate list item
function createLi(data) {
let li = document.createElement("li");
li.innerHTML = String(data.message);
return li;
}
// Check browser support
let source = '';
if (window.EventSource) {
source = new EventSource('http://localhost:8088/sse/');
} else {
throw new Error("Current browser does not support SSE");
}
// Connection opened
source.onopen = function(event) {
console.log(source.readyState);
console.log("Long connection opened");
};
// Message received
source.onmessage = function(event) {
console.log(JSON.parse(event.data));
console.log("Received long‑connection data");
let li = createLi(JSON.parse(event.data));
document.getElementById("ul").appendChild(li);
};
// Connection error
source.onerror = function(event) {
console.log(source.readyState);
console.log("Long connection interrupted");
};
</script>
</body>
</html>Demo: Backend Code (Node + Express)
const express = require('express');
const app = express();
const port = 8088;
// Enable CORS
app.all("*", function(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("Entered long‑connection");
setInterval(() => {
const data = { message: `Current time is ${new Date().toLocaleTimeString()}` };
res.write(`data: ${JSON.stringify(data)}
`);
}, 1000);
});
app.listen(port, () => {
console.log(`Server started – http://localhost:${port}`);
});Result
Running the demo shows a continuously updating list of timestamps on the page, confirming that the SSE connection successfully pushes data from the server to the client.
Conclusion
SSE is lighter than WebSocket.
SSE runs over standard HTTP/HTTPS.
WebSocket introduces a new ws/wss protocol.
For one‑way server‑to‑client pushes, SSE is the recommended choice.
For bidirectional communication (e.g., chat), WebSocket is more suitable.
Both protocols have good browser compatibility, except IE does not support SSE.
Polling should be avoided due to high client resource consumption, though it can be a quick fallback.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
macrozheng
Dedicated to Java tech sharing and dissecting top open-source projects. Topics include Spring Boot, Spring Cloud, Docker, Kubernetes and more. Author’s GitHub project “mall” has 50K+ stars.
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.
