Real-Time Communication: Server-Sent Events (SSE) enable servers to push real-time updates to clients over a single, long-lived HTTP connection. Combined with JSON, SSE provides an efficient way to stream structured data to web applications.
What Are Server-Sent Events?
Server-Sent Events (SSE) is a web standard that allows a server to push data to a client over a persistent HTTP connection. Unlike traditional HTTP requests where the client repeatedly polls the server, SSE enables unidirectional communication from server to client.
SSE is particularly useful for applications requiring real-time updates such as live news feeds, stock prices, social media updates, and progress indicators. The connection remains open, allowing the server to send data whenever new information becomes available.
Why Use SSE with JSON?
JSON is the ideal data format for SSE because:
Structured Data
JSON provides a structured format for sending complex data objects through SSE streams
Universal Support
JSON is natively supported in JavaScript, making client-side parsing seamless
Lightweight
JSON is human-readable and compact, reducing bandwidth requirements
Easy Parsing
JavaScript's JSON.parse() makes it trivial to extract data from SSE messages
Setting Up SSE in Node.js
To implement Server-Sent Events in Node.js, you'll need to create an HTTP server that handles SSE connections and sends events in the proper format.
Creating an SSE Server
Here's how to set up a basic SSE server in Node.js:
const http = require('http');
const server = http.createServer((req, res) => {
if (req.url === '/sse-endpoint') {
// Set SSE headers
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
'Access-Control-Allow-Origin': '*'
});
// Send initial connection confirmation
res.write('data: ' + JSON.stringify({
status: 'connected',
message: 'SSE connection established'
}) + '\n\n');
// Send periodic updates
const interval = setInterval(() => {
const data = {
timestamp: new Date().toISOString(),
message: 'Server update',
value: Math.random()
};
res.write('data: ' + JSON.stringify(data) + '\n\n');
}, 1000);
// Clean up on client disconnect
req.on('close', () => {
clearInterval(interval);
res.end();
});
} else {
res.writeHead(404);
res.end('Not found');
}
});
server.listen(3000, () => {
console.log('SSE server running on http://localhost:3000');
});Understanding the SSE Format
The SSE protocol requires data to be formatted in a specific way:
- Event data: Each message must be prefixed with
data: - Line breaks: Messages must end with two newline characters
\n\n - JSON serialization: Object data should be serialized to JSON before sending
- Connection headers: Proper headers maintain the connection
Client-Side Implementation
On the client side, you'll use the EventSource API to connect to the SSE endpoint and receive messages.
Basic EventSource Setup
// Create EventSource connection
const eventSource = new EventSource('/sse-endpoint');
// Handle incoming messages
eventSource.onmessage = function(event) {
const data = JSON.parse(event.data);
console.log('Received:', data);
// Display the data in your UI
displayUpdate(data);
};
// Handle connection open
eventSource.onopen = function(event) {
console.log('SSE connection opened');
};
// Handle errors
eventSource.onerror = function(event) {
console.error('SSE error:', event);
};
// Close connection when done
function closeConnection() {
eventSource.close();
}Handling Different Event Types
SSE supports custom event types for organizing different streams of data:
// Server: Send custom event type
res.write('event: user-update\n');
res.write('data: ' + JSON.stringify({ userId: 123, name: 'John' }) + '\n\n');
// Client: Listen for specific event type
eventSource.addEventListener('user-update', function(event) {
const data = JSON.parse(event.data);
updateUserProfile(data);
});Advanced SSE Patterns
Here are some advanced patterns for working with SSE and JSON:
Managing Multiple Connections
const connections = new Set();
const server = http.createServer((req, res) => {
if (req.url === '/sse-endpoint') {
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive'
});
connections.add(res);
req.on('close', () => {
connections.delete(res);
});
}
});
// Broadcast to all connected clients
function broadcast(data) {
const message = 'data: ' + JSON.stringify(data) + '\n\n';
connections.forEach(client => {
client.write(message);
});
}Error Handling and Reconnection
Automatic Reconnection
The EventSource API automatically attempts to reconnect if the connection is lost. You can customize the reconnection behavior using the retry field in your SSE messages.
// Server: Set retry interval
res.write('retry: 3000\n\n');
// Client: Handle reconnection events
eventSource.addEventListener('error', function(event) {
if (eventSource.readyState === EventSource.CONNECTING) {
console.log('Reconnecting...');
} else if (eventSource.readyState === EventSource.CLOSED) {
console.log('Connection closed');
// Manually reconnect or show error
}
});SSE vs WebSockets vs Polling
Understanding when to use SSE versus other real-time communication methods:
| Technology | Communication | Best Use Case |
|---|---|---|
| SSE | Unidirectional (Server to Client) | Real-time feeds, notifications, live updates |
| WebSocket | Bidirectional | Chat applications, gaming, collaborative editing |
| Polling | Client requests | Simple updates, compatibility fallback |
Best Practices
Use JSON Validation
Always validate JSON data on both server and client to prevent parsing errors and security issues.
Implement Connection Limits
Limit the number of concurrent SSE connections per user to prevent server resource exhaustion.
Close Connections Properly
Always clean up connections and intervals when clients disconnect to free up server resources.
Real-World Example: Live JSON Data Stream
Here's a complete example of streaming JSON data from a Node.js server to a client:
// Server: app.js
const http = require('http');
const url = require('url');
const server = http.createServer((req, res) => {
const parsedUrl = url.parse(req.url, true);
if (parsedUrl.pathname === '/stream') {
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
'Access-Control-Allow-Origin': '*'
});
let counter = 0;
const interval = setInterval(() => {
const jsonData = {
id: counter++,
timestamp: new Date().toISOString(),
data: {
temperature: Math.floor(Math.random() * 30) + 20,
humidity: Math.floor(Math.random() * 40) + 30
}
};
res.write('data: ' + JSON.stringify(jsonData) + '\n\n');
}, 2000);
req.on('close', () => {
clearInterval(interval);
});
} else {
res.writeHead(404);
res.end('Not found');
}
});
server.listen(3000);
// Client: index.html
<!DOCTYPE html>
<html>
<head>
<title>SSE Example</title>
</head>
<body>
<div id="output"></div>
<script>
const source = new EventSource('http://localhost:3000/stream');
source.onmessage = function(event) {
const data = JSON.parse(event.data);
document.getElementById('output').innerHTML +=
'<p>ID: ' + data.id + ', Temp: ' + data.data.temperature + '°C</p>';
};
</script>
</body>
</html>Conclusion
Server-Sent Events provide an excellent solution for streaming real-time data from server to client. Combined with JSON, SSE offers a simple and efficient way to implement live updates in web applications.
SSE is particularly well-suited for applications where the server needs to push updates to clients, such as live feeds, notifications, progress indicators, and real-time dashboards. The automatic reconnection feature and simple EventSource API make it easy to implement robust real-time communication.
Need to Format Your JSON First?
Use our free JSON formatter to validate and format your JSON data before streaming it through Server-Sent Events. Ensure your JSON is properly structured and error-free.
Try JSON Formatter