209 lines
7.4 KiB
Plaintext
209 lines
7.4 KiB
Plaintext
---
|
|
title: What are server sent events ?
|
|
---
|
|
|
|
## TL;DR
|
|
|
|
[`Server-sent events (SSE)`](https://html.spec.whatwg.org/multipage/comms.html#the-eventsource-interface) is a standard that allows a web page to receive automatic updates from a server via an HTTP connection. `Server-sent events` describe a built-in-class `EventSource` that keeps connection with the server and allows client to receive events from server. Connection created by `Server-sent events` are persistent similar to the `WebSocket`, however there are several differences:
|
|
|
|
| WebSocket | EventSource |
|
|
| --- | --- |
|
|
| Bi-directional: both client and server can exchange messages | One-directional: only server sends data |
|
|
| Binary and text data | Only text |
|
|
| WebSocket protocol | Regular HTTP |
|
|
|
|
**Creating an EventSource**
|
|
|
|
```js
|
|
const eventSource = new EventSource('/sse-stream');
|
|
```
|
|
|
|
**Listening for events**
|
|
|
|
```js
|
|
// Fired when the connection is established.
|
|
eventSource.addEventListener('open', () => {
|
|
console.log('Connection opened');
|
|
});
|
|
|
|
// Fired when a message is received from the server
|
|
eventSource.addEventListener('message', (event) => {
|
|
console.log('Received message:', event.data);
|
|
});
|
|
|
|
// Fired when an error occurs.
|
|
eventSource.addEventListener('error', (error) => {
|
|
console.error('Error occurred:', error);
|
|
});
|
|
```
|
|
|
|
**Sending events from server**
|
|
|
|
```js
|
|
const express = require('express');
|
|
const app = express();
|
|
|
|
app.get('/sse-stream', (req, res) => {
|
|
// `Content-Type` need to be set to `text/event-stream`
|
|
res.setHeader('Content-Type', 'text/event-stream');
|
|
res.setHeader('Cache-Control', 'no-cache');
|
|
res.setHeader('Connection', 'keep-alive');
|
|
|
|
// Each message should be prefixed with data
|
|
const sendEvent = (data) => res.write(`data: ${data}\n\n`);
|
|
|
|
sendEvent('Hello from server');
|
|
|
|
const intervalId = setInterval(() => sendEvent(new Date().toString()), 1000);
|
|
|
|
res.on('close', () => {
|
|
console.log('Client closed connection');
|
|
clearInterval(intervalId);
|
|
});
|
|
});
|
|
|
|
app.listen(3000, () => console.log('Server started on port 3000'));
|
|
```
|
|
|
|
In this example, the server sends a "Hello from server" message initially, and then sends the current date every second. The connection is kept alive until the client closes it
|
|
|
|
---
|
|
|
|
## `Server-sent events`
|
|
|
|
Server-Sent Events (SSE) is a standard that allows a server to push updates to a web client over a single, long-lived HTTP connection. It enables real-time updates without the client having to constantly poll the server for new data.
|
|
|
|
### How `SSE` works:
|
|
|
|
1. The client creates a new `EventSource` object, passing the URL of the `server-side` script that will generate the event stream:
|
|
|
|
```js
|
|
const eventSource = new EventSource('/event-stream');
|
|
```
|
|
|
|
2. The server-side script sets the appropriate headers to indicate that it will be sending an event stream (`Content-Type: text/event-stream`), and then starts sending events to the client.
|
|
3. Each event sent by the server follows a specific format, with fields like `event`, `data`, and `id`. For example:
|
|
|
|
```js
|
|
event: message
|
|
data: Hello, world!
|
|
|
|
event: update
|
|
id: 123
|
|
data: {"temperature": 25, "humidity": 60}
|
|
```
|
|
|
|
4. On the client-side, the `EventSource` object receives these events and dispatches them as `DOM` events, which can be handled using event listeners or the `onmessage` event handler:
|
|
|
|
```js
|
|
eventSource.onmessage = function (event) {
|
|
console.log('Received message:', event.data);
|
|
};
|
|
|
|
eventSource.addEventListener('update', function (event) {
|
|
console.log('Received update:', JSON.parse(event.data));
|
|
});
|
|
```
|
|
|
|
5. The `EventSource` object automatically handles reconnection if the connection is lost, and it can resume the event stream from the last received event ID using the `Last-Event-ID HTTP header`.
|
|
|
|
### Advantages of `SSE`
|
|
|
|
- **Simpler than WebSockets**: Easier to implement and understand than `WebSockets` for many use cases.
|
|
- **Automatic Reconnection**: The client handles reconnections automatically.
|
|
- **Lightweight**: Uses simple text-based messages and a single `HTTP` connection.
|
|
- **Built-in Browser Support**: Supported by most modern browsers without additional libraries.
|
|
|
|
### Disadvantages of SSE
|
|
|
|
- **Unidirectional**: Only the server can send data to the client. For bidirectional communication, WebSockets would be more appropriate.
|
|
- **Connection Limitations**: Limited to the maximum number of open `HTTP` connections per browser, which can be an issue with many clients.
|
|
|
|
### Implementing `SSE` in JavaScript
|
|
|
|
#### Client-Side Code:
|
|
|
|
```js
|
|
// Create a new EventSource object
|
|
const eventSource = new EventSource('/sse');
|
|
|
|
// Event listener for receiving messages
|
|
eventSource.onmessage = function (event) {
|
|
console.log('New message:', event.data);
|
|
};
|
|
|
|
// Event listener for errors
|
|
eventSource.onerror = function (error) {
|
|
console.error('Error occurred:', error);
|
|
};
|
|
|
|
// Optional: Event listener for open connection
|
|
eventSource.onopen = function () {
|
|
console.log('Connection opened');
|
|
};
|
|
```
|
|
|
|
#### Server-Side Code:
|
|
|
|
```js
|
|
const http = require('http');
|
|
|
|
http
|
|
.createServer((req, res) => {
|
|
if (req.url === '/sse') {
|
|
// Set headers for SSE
|
|
res.writeHead(200, {
|
|
'Content-Type': 'text/event-stream',
|
|
'Cache-Control': 'no-cache',
|
|
Connection: 'keep-alive',
|
|
});
|
|
|
|
// Function to send a message
|
|
const sendMessage = (message) => {
|
|
res.write(`data: ${message}\n\n`);
|
|
};
|
|
|
|
// Send a message every 5 seconds
|
|
const intervalId = setInterval(() => {
|
|
sendMessage(`Current time: ${new Date().toLocaleTimeString()}`);
|
|
}, 5000);
|
|
|
|
// Handle client disconnect
|
|
req.on('close', () => {
|
|
clearInterval(intervalId);
|
|
res.end();
|
|
});
|
|
} else {
|
|
res.writeHead(404);
|
|
res.end();
|
|
}
|
|
})
|
|
.listen(8080, () => {
|
|
console.log('SSE server running on port 8080');
|
|
});
|
|
```
|
|
|
|
In this example:
|
|
|
|
- The server sets the appropriate headers to establish an `SSE` connection.
|
|
- Messages are sent to the client every 5 seconds.
|
|
- The server cleans up the interval and ends the response when the client disconnects.
|
|
|
|
### Considerations
|
|
|
|
- **Event Types**: `SSE` supports custom event types using the `event:` field, allowing you to categorize messages.
|
|
- **Retry Mechanism**: The client will retry the connection if it fails, with the retry interval specified by the `retry:` field from the server.
|
|
- **Last-Event-ID**: The client sends the `Last-Event-ID` header when reconnecting, allowing the server to resume the stream from the last received event.
|
|
- **CORS and Authentication**: Ensure `CORS` headers are correctly configured for cross-origin requests, and consider secure methods for authentication and authorization.
|
|
|
|
## Summary
|
|
|
|
`Server-sent Events` provide an efficient and straightforward way to push updates from a server to a client in real-time. They are particularly well-suited for applications that require continuous data streams but do not need full `bidirectional` communication. With built-in support in modern browsers, `SSE` is a reliable choice for many real-time web applications.
|
|
|
|
## Further reading
|
|
|
|
- [Using server-sent events - MDN](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events)
|
|
- [Server sent events - javascript.info](https://javascript.info/server-sent-events)
|
|
- [Server-Sent Events: A webSockets alternative ready for another look](https://ably.com/topic/server-sent-events)
|
|
- [What are SSE (Server-Sent Events) and how do they work?](https://bunny.net/academy/http/what-is-sse-server-sent-events-and-how-do-they-work/)
|