The usage of Server-Sent Events (SSE)
What are Server-Sent Events
Server-Sent Events (SSE) is an HTML5 technology that allows servers to push real-time data to clients. Unlike WebSocket, SSE is a one-way communication method, supporting only server-to-client message pushing. It is based on the HTTP protocol, uses a simple event stream format, and is suitable for scenarios where the server needs to actively push data but the client does not need to send data frequently.
Key features of SSE include:
- Simple to use, requiring only the JavaScript API
- Automatic reconnection mechanism
- Support for custom event types
- Lightweight, with no additional protocols needed
Comparison Between SSE and WebSocket
SSE and WebSocket are both technologies for real-time communication, but each has its own use cases:
Feature | SSE | WebSocket |
---|---|---|
Communication Direction | One-way (server → client) | Two-way |
Protocol | HTTP | Independent WebSocket protocol |
Connection Complexity | Simple | More complex |
Data Format | Text (event stream) | Binary or text |
Automatic Reconnection | Supported | Requires manual implementation |
Browser Support | Newer browsers | Widely supported |
SSE is more suitable for the following scenarios:
- Applications that only require server-pushed data
- Real-time features that need simple implementation
- Systems that do not require frequent two-way communication
Basic Usage
Client-Side Implementation
The client uses the EventSource API to receive messages pushed by the server:
// Create an EventSource object connected to the server endpoint
const eventSource = new EventSource('/sse-endpoint');
// Listen for the default message event
eventSource.onmessage = function(event) {
console.log('Message received:', event.data);
// Update page content
document.getElementById('messages').innerHTML += event.data + '<br>';
};
// Listen for custom events
eventSource.addEventListener('customEvent', function(event) {
console.log('Custom event:', event.data);
});
// Error handling
eventSource.onerror = function(error) {
console.error('EventSource error:', error);
// Custom reconnection logic can be implemented here
};
Server-Side Implementation (Node.js Example)
const http = require('http');
const fs = require('fs');
http.createServer((req, res) => {
if (req.url === '/sse-endpoint') {
// Set the required response headers for SSE
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive'
});
// Send an initial message
res.write('data: Connection established\n\n');
// Send messages periodically
let counter = 0;
const intervalId = setInterval(() => {
counter++;
res.write(`data: This is message ${counter}\n\n`);
// Send a custom event
if (counter % 3 === 0) {
res.write(`event: customEvent\ndata: Custom event data ${counter}\n\n`);
}
// End after 10 tests
if (counter >= 10) {
clearInterval(intervalId);
res.end();
}
}, 1000);
// Clean up when the client disconnects
req.on('close', () => {
clearInterval(intervalId);
});
} else {
// Return the HTML page
res.writeHead(200, {'Content-Type': 'text/html'});
res.end(fs.readFileSync('./sse-client.html'));
}
}).listen(3000);
console.log('SSE server running at http://localhost:3000');
Event Stream Format
SSE uses a specific text stream format, with each message consisting of the following parts:
event: eventName // Optional, specifies the event type
data: messageData // Message content, can be multi-line
id: messageId // Optional, message ID
retry: timeout // Optional, reconnection time (milliseconds)
\n // Empty line indicates the end of the message
Example:
event: statusUpdate
data: {"user": "John", "status": "online"}
id: 12345
retry: 5000
data: This is a multi-line
data: message example
Advanced Features
Custom Event Types
In addition to the default message event, SSE supports custom event types:
// Server-side sending of a custom event
res.write('event: userUpdate\ndata: {"id": 101, "name": "Jane"}\n\n');
// Client-side listening for custom events
eventSource.addEventListener('userUpdate', function(event) {
const userData = JSON.parse(event.data);
console.log('User update:', userData.name);
});
Message ID and Reconnection Mechanism
SSE automatically tracks the last received message ID and sends it to the server via the Last-Event-ID header when reconnecting after a disconnection:
// Server-side sending of a message with an ID
res.write('id: 1001\ndata: Important message\n\n');
// Server can check the Last-Event-ID header
const lastEventId = req.headers['last-event-id'];
if (lastEventId) {
// Resume sending messages from the breakpoint
}
Controlling Reconnection Time
You can specify the retry time after a client disconnection:
// Server suggests the client reconnect after 3 seconds
res.write('retry: 3000\n\n');
Practical Application Examples
Real-Time Stock Price Updates
// Client code
const stockSource = new EventSource('/stocks');
stockSource.addEventListener('priceUpdate', function(event) {
const stockData = JSON.parse(event.data);
const stockElement = document.getElementById(`stock-${stockData.symbol}`);
if (stockElement) {
stockElement.textContent = `${stockData.symbol}: $${stockData.price.toFixed(2)}`;
stockElement.style.color = stockData.change >= 0 ? 'green' : 'red';
}
});
// Server-side code (Node.js)
setInterval(() => {
const stocks = ['AAPL', 'GOOGL', 'MSFT', 'AMZN'];
stocks.forEach(symbol => {
const priceChange = (Math.random() - 0.5) * 10;
const stockData = {
symbol,
price: 100 + Math.random() * 1000,
change: priceChange
};
res.write(`event: priceUpdate\ndata: ${JSON.stringify(stockData)}\n\n`);
});
}, 2000);
Real-Time Log Monitoring
// Client code
const logSource = new EventSource('/logs');
logSource.onmessage = function(event) {
const logElement = document.getElementById('log-output');
logElement.value += event.data + '\n';
logElement.scrollTop = logElement.scrollHeight;
};
// Server-side code (simulating logs)
const fs = require('fs');
const tail = require('tail').Tail;
const logFile = new Tail('/var/log/app.log');
logFile.on('line', (line) => {
res.write(`data: ${line}\n\n`);
});
Browser Compatibility and Fallback Solutions
SSE is well-supported in modern browsers but may not be available in IE and some mobile browsers. You can detect compatibility and provide fallback solutions as follows:
if (typeof EventSource !== 'undefined') {
// Use SSE
const source = new EventSource('/updates');
} else {
// Fallback: polling or other technologies
console.warn('Browser does not support Server-Sent Events, using polling instead');
setInterval(fetchUpdates, 5000);
function fetchUpdates() {
fetch('/updates')
.then(response => response.json())
.then(data => {
// Handle updates
});
}
}
Security Considerations
When using SSE, the following security issues should be noted:
-
Cross-Origin Requests: SSE follows the same-origin policy by default. Cross-origin requests require CORS headers:
res.writeHead(200, { 'Content-Type': 'text/event-stream', 'Access-Control-Allow-Origin': 'https://client-domain.com' });
-
Authentication and Authorization: Credentials can be passed in the EventSource constructor:
const eventSource = new EventSource('/secure-sse', { withCredentials: true });
-
Message Validation: Always validate data sent by the server to prevent XSS attacks:
eventSource.onmessage = function(event) { const safeData = escapeHtml(event.data); // Update the DOM with safeData };
Performance Optimization
-
Connection Management: Close unnecessary EventSource connections promptly:
// When no longer needing to receive messages function stopUpdates() { eventSource.close(); }
-
Server-Side Resource Release: Ensure server resources are released when the client disconnects:
req.on('close', () => { // Clean up timers, database connections, etc. clearInterval(updateInterval); });
-
Message Compression: For large amounts of text data, consider server-side compression:
res.writeHead(200, { 'Content-Type': 'text/event-stream', 'Content-Encoding': 'gzip' });
Integration with Other Technologies
Working with Service Workers
You can handle SSE messages in a Service Worker to implement offline functionality:
// service-worker.js
self.addEventListener('message', event => {
if (event.data.type === 'CREATE_SSE') {
const sse = new EventSource(event.data.url);
sse.onmessage = msg => {
// Process the message and decide whether to show a notification
if (msg.data.important) {
self.registration.showNotification('New notification', {
body: msg.data.text
});
}
};
}
});
// Main thread
navigator.serviceWorker.controller.postMessage({
type: 'CREATE_SSE',
url: '/notifications'
});
Integration with React/Vue and Other Frameworks
Using SSE in a React component:
import { useEffect, useState } from 'react';
function StockTicker() {
const [stocks, setStocks] = useState({});
useEffect(() => {
const source = new EventSource('/stocks');
source.addEventListener('priceUpdate', event => {
const stockData = JSON.parse(event.data);
setStocks(prev => ({
...prev,
[stockData.symbol]: stockData
}));
});
return () => source.close(); // Clean up the effect
}, []);
return (
<div>
{Object.values(stocks).map(stock => (
<div key={stock.symbol}>
{stock.symbol}: ${stock.price.toFixed(2)}
</div>
))}
</div>
);
}
Debugging and Troubleshooting
-
Viewing the Event Stream: You can directly access the SSE endpoint in the browser address bar to view the raw event stream.
-
Network Inspection: Use the developer tools' Network panel to check the SSE connection status and transmitted messages.
-
Common Issues:
- Ensure the server response includes the correct
Content-Type: text/event-stream
header - Each message must end with two newline characters (
\n\n
) - Avoid single newline characters in message data. For multi-line data, each line should start with
data:
- Ensure the server response includes the correct
-
Enhanced Error Handling:
eventSource.onerror = function(error) { if (eventSource.readyState === EventSource.CLOSED) { console.log('Connection closed by the server'); } else { console.error('SSE error:', error); // Attempt to reconnect setTimeout(() => { initEventSource(); }, 5000); } };
Extended Application Scenarios
-
Real-Time Notification Systems: Message notifications in social networks and collaboration tools.
-
Real-Time Dashboards: Real-time data display for monitoring systems and analytics platforms.
-
Real-Time Collaborative Editing: Cursor position synchronization in collaborative document editing.
-
Sports Event Live Updates: Real-time score and match statistics updates.
-
Auction Systems: Real-time bid updates and countdowns.
-
IoT Device Monitoring: Real-time pushing of device status and sensor data.
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn