Purpose
Server-Sent Events enables efficient server-to-client streaming of text-based event data—e.g., real-time notifications or updates generated on the server.
It was an early addition to the HTML5 specification and is natively supported by most modern browsers.
Pros
- Low latency (single, long-lived HTTP connection)
- Efficient message parsing (no unbounded buffer)
- Unlike a raw XHR connection, which buffers the full received response until the connection is dropped, an SSE connection can discard processed messages without accumulating all of them in memory.
- Automatic tracking of last seen message and auto-reconnect
- EventSource will automatically reconnect to the server and optionally advertise the ID of the last seen message, such that the stream can be resumed and lost messages can be retransmitted.
- Client message notifications as DOM events
Cons
- Each SSE consumes 1 TCP connection in HTTP/1.1 due to the long-lived HTTP connection
- An example in “sse_with_3conn.pcap” file below
Examples
Facebook/Twitter updates, stock price updates, news feeds, sport results, etc.
Difference Between Push Technology
- SSE
- A very easy way for server push notification with long-term communication
- Web Push
- Ensures more efficient use of network and radio resources to deliver realtime events via HTTP/2
- e.g.,
Elements
-
Browser
- EventSource interface allows the client to receive push notifications from the server as DOM events
- Implement XHR streaming and handle all the connection management and message parsing (allowing our applications to focus on the business logic)
-
Server
- “Event Stream” data format is used to deliver the individual updates
=> Request // Client connection initiated via EventSource interface GET /stream HTTP/1.1 Host: example.com Accept: text/event-stream <= Response // Server response with "text/event-stream" content-type HTTP/1.1 200 OK Connection: keep-alive Content-Type: text/event-stream Transfer-Encoding: chunked // Server sets client reconnect interval 15s if the connection drops retry: 15000 // Simple text event with no message type data: First message is a simple string. // JSON payload with no message type data: {"message": "JSON payload"} // Simple text event of type "foo" event: foo data: Message of type "foo" // Multiline event with message ID and type id: 42 event: bar data: Multi-line message of data: type "bar" and id "42" // Simple text event with optional ID id: 43 data: Last message, id "43"
Demo
We use PHP because “PHP is the best language for web programming.”
Demo source code from: HTML5 Server-Sent Events(伺服器發送事件) 教學範例 for PHP
The first PCAP file is a normal version, the second one calls new EventSource()
3 times so there are 3 TCP connections in Wireshark conversations window.
-
PCAP files
server.php
<?php
ini_set('max_execution_time', 0);
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
header('X-Accel-Buffering: no'); // Make Nginx flush buffer immediately
// Infinite loop
while (true) {
// Data for transmission
$data = array(
'name' => 'Mr. Wang',
'date' => date('Y-m-d H:i:s')
);
// Send with JSON encoded format
echo "id: D121xxxxxx\ndata: " . json_encode($data);
echo "\n\n";
ob_flush();
flush();
// wait for 1 second
sleep(1);
}
client.html
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>HTML5 API Server-Send Event</title>
<script type="text/javascript">
window.onload = function() {
document.querySelector('button').addEventListener('click', closeSSE, false);
if (typeof(EventSource) !== 'undefined') {
// server path
var sse = new EventSource('server.php');
sse.addEventListener('open', open, false);
sse.addEventListener('message', message, false);
sse.addEventListener('error', error, false);
} else {
alert("Browser doesn't support");
}
function closeSSE(event) {
closeEventSource();
}
function open(event) {
console.log('connected');
}
function message(event) {
var pullData = JSON.parse(event.data);
var newElement = document.createElement('li');
newElement.innerHTML = pullData.name + ', ' + pullData.date;
document.body.appendChild(newElement);
}
function error(event) {
closeEventSource();
alert('connection error');
};
function closeEventSource() {
sse.close();
alert('disconnected');
}
}
</script>
</head>
<body>
<button>Disconnect</button>
</body>
</html>
References
- High Performance Browser Networking - Server-Sent Events (SSE)
- HTML5 Server-Sent Events(伺服器發送事件) 教學範例 for PHP
- 各自表述的Server Push
- W3Schools - HTML SSE API
comments powered by Disqus