Last active
April 26, 2024 11:15
-
-
Save akirattii/257d7efc8430c7e3fd0b4ec60fc7a768 to your computer and use it in GitHub Desktop.
Server-Sent Events nodejs example. This shows how to detect the client disconnection.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var express = require('express'); | |
var app = express(); | |
// response header for sever-sent events | |
const SSE_RESPONSE_HEADER = { | |
'Connection': 'keep-alive', | |
'Content-Type': 'text/event-stream', | |
'Cache-Control': 'no-cache', | |
'X-Accel-Buffering': 'no' | |
}; | |
// Connected users (request object of each user) : | |
var users = {}; | |
// SSE starting endpoint | |
// You can access url `http://localhost:3000/sse/<userId>` | |
// | |
// Caution: | |
// This example exposes <userId> as URI parameter for testing purpose. | |
// In reality, you should use one stored in req.session. | |
app.get('/sse/:userId', function(req, res) { | |
let userId = getUserId(req); | |
// data for sending | |
let data; | |
// Stores this connection | |
users[userId] = req; | |
// Writes response header. | |
res.writeHead(200, SSE_RESPONSE_HEADER); | |
// Interval loop | |
let intervalId = setInterval(function() { | |
console.log(`*** Interval loop. userId: "${userId}"`); | |
// Creates sending data: | |
data = { | |
userId, | |
users: Object.keys(users).length, | |
// memoryUsage: process.memoryUsage() | |
time: new Date().getTime(), | |
}; | |
// Note: | |
// For avoidance of client's request timeout, | |
// you should send a heartbeat data like ':\n\n' (means "comment") at least every 55 sec (30 sec for first time request) | |
// even if you have no sending data: | |
if (!data) | |
res.write(`:\n\n`); | |
else | |
res.write(`data: ${JSON.stringify(data)}\n\n`); | |
}, 3000); | |
// Note: Heatbeat for avoidance of client's request timeout of first time (30 sec) | |
res.write(`:\n\n`); | |
req.on("close", function() { | |
let userId = getUserId(req); | |
console.log(`*** Close. userId: "${userId}"`); | |
// Breaks the interval loop on client disconnected | |
clearInterval(intervalId); | |
// Remove from connections | |
delete users[userId]; | |
}); | |
req.on("end", function() { | |
let userId = getUserId(req); | |
console.log(`*** End. userId: "${userId}"`); | |
}); | |
}); | |
function getUserId(req) { | |
// Note: | |
// In reality, you should use userId stored in req.session, | |
// but not URI parameter. | |
return req.params.userId; | |
} | |
app.listen(3000, function() { | |
console.log('Example app listening on port 3000!'); | |
}); |
Thanks for the example.
@arnaudambro, I have a similar requirement as yours as I need to push notifications to specific users on some of my API calls. How did you end up managing it? Did you store all the res
in some data structure? Thanks :)
Hi @abhinavchawla13
You can check this post, you'll find the answer :)
https://stackoverflow.com/questions/58822916/using-server-sent-events-how-to-store-a-connection-to-a-client
@arnaudambro, thanks 😄
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi @akirattii, I am using your code, because I like it quite much, especially because you gave me an idea about how to store a connection somehow, with
var users = {}
.For myself, I am storing the Response
res
in this object, not the Requestreq
as you wrote in your code, so that when required to send a messagemessage
through the connection opened by auserId
, I can retrieve theres
from theuserId
, and use it to send the message byres.write(
data:${JSON.stringify(message)}\n\n`.But I think I am doing something wrong, storing the
res
in a global variable... I thought about storing it in DB (I am using MongoDB there), but I don't see how either.What do you think ?
Here below is my code