Server Sent Events
Network Requests: Server Sent Events
What are Server-Sent Events in JavaScript?
View Answer:
Are Server-Sent Events Real-time?
View Answer:
How is an SSE connection established?
View Answer:
Here's an example using JavaScript (Node.js) and Express.js for the server side and JavaScript for the client side. Server-Sent Events (SSE) allows a server to push updates to a client whenever they are available.
On the server side:
const express = require('express');
const app = express();
app.get('/events', (req, res) => {
res.setHeader('Content-Type', 'text/event-stream');
res.setHeader('Cache-Control', 'no-cache');
res.setHeader('Connection', 'keep-alive');
res.flushHeaders();
// Here you could actually decide on the logic of what updates you send to the client
// and when you send them. Below is just an example of sending the current time every second.
setInterval(() => {
const timeNow = new Date().toISOString();
res.write(`data: ${timeNow}\n\n`); // "\n\n" is necessary to distinguish between different messages
}, 1000);
req.on('close', () => {
console.log('Connection closed');
});
});
app.listen(3000, () => {
console.log('Server listening on port 3000');
});
On the client side:
let source = new EventSource('http://localhost:3000/events');
source.addEventListener('message', (event) => {
console.log(event.data);
});
source.addEventListener('open', () => {
console.log('Connection was opened');
});
source.addEventListener('error', (event) => {
if (event.readyState === EventSource.CLOSED) {
console.log('Connection was closed');
} else {
console.log('An error has occurred');
}
});
This example code opens an SSE connection to the server at 'http://localhost:3000/events'. The server will send a message with the current date and time every second, and the client will log these messages to the console.
Please note that this is just an illustrative example, in a real-world scenario, you would want to consider various factors such as error handling, controlling intervals, and handling user-specific data. Also, consider that you need to handle potential issues like reconnections on the client-side or handle the number of connections on the server-side.
Can you name a few use cases for Server-Sent Events?
View Answer:
How can you handle different types of SSE messages?
View Answer:
Here's an example of handling different types of SSE messages:
On the server side, you might send events like this:
data: This is a message
event: messageType1
data: This is a message for type1
data: This is another message
event: messageType2
data: This is a message for type2
Then, on the client side, you can handle these different messages like this:
let eventSource = new EventSource("https://yourserver.com/events");
eventSource.addEventListener("messageType1", function(event) {
console.log("Message Type 1 received", event.data);
});
eventSource.addEventListener("messageType2", function(event) {
console.log("Message Type 2 received", event.data);
});
eventSource.onerror = function(event) {
console.error("Error occurred", event);
};
In this example, two different types of events (messageType1
and messageType2
) are handled separately, logging different messages to the console. The onerror
event is also handled.
What are the limitations of Server-Sent Events?
View Answer:
How can you control reconnection attempts in SSE?
View Answer:
Here's a server-side example in Node.js using the http
module:
const http = require('http');
http.createServer(function(req, res) {
res.setHeader('Content-Type', 'text/event-stream');
res.setHeader('Cache-Control', 'no-cache');
res.setHeader('Connection', 'keep-alive');
res.write('retry: 10000\n'); // Set reconnection time to 10 seconds
res.write('data: This is a message\n\n');
}).listen(8000);
In this example, the server is set up to push Server-Sent Events to the client. It sets a reconnection attempt time by sending 'retry: 10000' which tells the client to wait 10 seconds before attempting to reconnect if the connection is lost. It also sends a message 'data: This is a message' to the client.
Is there any mechanism in SSE for handling lost updates?
View Answer:
On the server side (using Node.js and Express.js):
const express = require('express');
const app = express();
let eventId = 0;
app.get('/events', (req, res) => {
res.setHeader('Content-Type', 'text/event-stream');
res.setHeader('Cache-Control', 'no-cache');
res.setHeader('Connection', 'keep-alive');
res.flushHeaders();
const interval = setInterval(() => {
const timeNow = new Date().toISOString();
res.write(`id: ${eventId}\ndata: ${timeNow}\n\n`);
eventId++;
}, 1000);
req.on('close', () => {
clearInterval(interval);
console.log('Connection closed');
});
});
app.listen(3000, () => {
console.log('Server listening on port 3000');
});
On the client side:
let source = new EventSource('http://localhost:3000/events');
source.onmessage = (event) => {
console.log(`ID: ${event.lastEventId}, Data: ${event.data}`);
};
source.onerror = (event) => {
console.log('An error has occurred');
};
In this example, the server sends an event every second with an increasing ID and the current date and time. If the connection drops, the browser reconnects and includes the header Last-Event-ID
with the ID of the last received event. In a real-world scenario, the server would use this ID to decide where to restart the event stream.
However, do note that in this example the server isn't actually handling lost updates, it's just sending messages with increasing IDs. You would need to implement your own logic to handle lost updates based on your application's requirements.
How can you close an SSE (EventSource) connection?
View Answer:
let source = new EventSource('http://localhost:3000/events');
source.onmessage = (event) => {
console.log(`Data: ${event.data}`);
};
// Some condition or user action that prompts you to close the connection
if (someCondition) {
source.close();
}
In this example, once source.close()
is called, the browser will not attempt to reconnect to the server. If you want to start receiving events again, you will need to create a new EventSource
instance.
On the server side, it's important to note that an SSE connection is basically a long-running HTTP connection. So, if you want to close it from the server side, you would do so by ending the HTTP response. This could look like the following:
app.get('/events', (req, res) => {
res.setHeader('Content-Type', 'text/event-stream');
res.setHeader('Cache-Control', 'no-cache');
res.setHeader('Connection', 'keep-alive');
res.flushHeaders();
const interval = setInterval(() => {
const timeNow = new Date().toISOString();
res.write(`data: ${timeNow}\n\n`);
}, 1000);
req.on('close', () => {
clearInterval(interval);
console.log('Connection closed by the client');
});
// Some condition or event that prompts you to close the connection
if (someCondition) {
clearInterval(interval);
res.end();
console.log('Connection closed by the server');
}
});
Remember, you need to properly handle events and clear any intervals or timeouts that are associated with the connection to avoid memory leaks when the connection is closed.
Can you send HTTP headers with an SSE request?
View Answer:
What HTTP status code is used for a successful SSE connection?
View Answer:
What is the purpose of the last-event-id HTTP header in SSE?
View Answer:
Why is HTTP/2 a perfect match for SSE?
View Answer:
Can Server-Sent Events work with cross-origin requests?
View Answer:
What kind of server response does SSE require?
View Answer:
Are there any security considerations with SSE?
View Answer:
How does SSE compare with long-polling and short-polling?
View Answer:
How do Server-Sent Events describe the EventSource?
View Answer:
What is the difference between WebSocket and EventSource?
View Answer:
Why do we use the EventSource class in our code?
View Answer:
What do we need to use to open an EventSource server connection?
View Answer:
let source = new EventSource('http://localhost:3000/events');
source.onopen = (event) => {
console.log('Connection to server opened');
};
source.onmessage = (event) => {
console.log('Message received from server:', event.data);
};
source.onerror = (event) => {
console.log('Error occurred');
};
In this code, a new EventSource
is created with the URL of the server sending the events. The onopen
, onmessage
, and onerror
event handlers are used to handle the connection opening, receiving a message, and handling errors, respectively.
Can we use EventSource with cross-origin requests?
View Answer:
On the server-side, you'll need to include the appropriate CORS headers. If you're using Express.js, you might do something like this:
const express = require('express');
const cors = require('cors');
const app = express();
app.use(cors());
app.get('/events', (req, res) => {
res.setHeader('Content-Type', 'text/event-stream');
res.setHeader('Cache-Control', 'no-cache');
res.setHeader('Connection', 'keep-alive');
res.flushHeaders();
setInterval(() => {
const message = `data: The server time is: ${new Date().toLocaleTimeString()}\n\n`;
res.write(message);
}, 1000);
});
app.listen(3000, () => {
console.log('Server is running on port 3000');
});
And on the client side, you would open an EventSource
connection as usual:
let source = new EventSource('https://another-site.com/events', {
withCredentials: true, // setting credentials to true
});
source.onmessage = (event) => {
console.log(event.data);
};
source.onerror = (event) => {
console.log('Error:', event);
};
In this example, the server is configured to allow CORS, and the client is able to connect to the server and receive server-sent events, even if it's hosted on a different origin. Please replace 'http://localhost:3000/events'
with your actual server URL.
What happens if an SSE (EventSource) connection is interrupted?
View Answer:
retry: 15000
data: Hello, I set the reconnection delay to 15 seconds
In a real-world scenario, you might want to implement backoff strategies (like exponential backoff) for reconnection attempts to handle temporary server unavailability.
You can view more about the exponential backoff JavaScript algorithm here. How to implement an exponential backoff retry strategy in Javascript.
How does the reconnection process work in the browser?
View Answer:
We should note that when a connection is finally closed, there is no way to “reopen” it. If we would like to connect again, create a new EventSource.
Server side (using Node.js and Express.js):
const express = require('express');
const app = express();
app.get('/events', (req, res) => {
res.setHeader('Content-Type', 'text/event-stream');
res.flushHeaders();
// Send a message every second
const interval = setInterval(() => {
const timeNow = new Date().toISOString();
// Retry field sets the reconnection time to 3000 milliseconds
res.write(`retry: 3000\ndata: ${timeNow}\n\n`);
}, 1000);
req.on('close', () => {
clearInterval(interval);
});
});
app.listen(3000);
Client side:
let source = new EventSource('http://localhost:3000/events');
source.onmessage = (event) => {
console.log(`Data: ${event.data}`);
};
source.onerror = (event) => {
if (source.readyState === EventSource.CONNECTING) {
console.log('Connection lost. Reconnecting...');
} else {
console.log('An error occurred');
}
};
In this example, the server sends a message every second. If the connection is lost, the browser waits for the time specified in the retry
field (3000 milliseconds in this case) before attempting to reconnect. The onerror
handler on the client side logs the reconnection attempts.
To correctly resume a network connection, what does the browser or server have to do?
View Answer:
data: Message 1
id: 1
data: Message 2
id: 2
data: Message 3
data: of two lines
id: 3
How does the EventSource object’s readyState property work?
View Answer:
EventSource.CONNECTING = 0; // connecting or reconnecting
EventSource.OPEN = 1; // connected
EventSource.CLOSED = 2; // connection closed
What are the three events that the EventSource object generates?
View Answer:
Here's a simple example of using EventSource:
let eventSource = new EventSource("https://yourserver.com/events");
eventSource.onopen = function(event) {
console.log("Connection established");
};
eventSource.onmessage = function(event) {
console.log("New message received", event.data);
};
eventSource.onerror = function(event) {
console.error("Error occurred", event);
};
In this example, the EventSource
object connects to the server located at "https://example.com/events". It also has handlers for the onopen
, onmessage
, and onerror
events, which log information to the console.
eventSource.addEventListener('join', (event) => {
console.log(`Joined ${event.data}`);
});
eventSource.addEventListener('message', (event) => {
console.log(`Said: ${event.data}`);
});
eventSource.addEventListener('leave', (event) => {
console.log(`Left ${event.data}`);
});