Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Simple Way to Implement Server Sent Events in Node.js?

I've looked around and it seems as if all the ways to implement SSEs in Node.js are through more complex code, but it seems like there should be an easier way to send and receive SSEs. Are there any APIs or modules that make this simpler?

like image 802
Jasch1 Avatar asked Mar 27 '16 16:03

Jasch1


2 Answers

Here is an express server that sends one Server-Sent Event (SSE) per second, counting down from 10 to 0:

const express = require('express')

const app = express()
app.use(express.static('public'))

app.get('/countdown', function(req, res) {
  res.writeHead(200, {
    'Content-Type': 'text/event-stream',
    'Cache-Control': 'no-cache',
    'Connection': 'keep-alive'
  })
  countdown(res, 10)
})

function countdown(res, count) {
  res.write("data: " + count + "\n\n")
  if (count)
    setTimeout(() => countdown(res, count-1), 1000)
  else
    res.end()
}

app.listen(3000, () => console.log('SSE app listening on port 3000!'))

Put the above code into a file (index.js) and run it: node index

Next, put the following HTML into a file (public/index.html):

<html>
<head>
  <script>
  if (!!window.EventSource) {
    var source = new EventSource('/countdown')

    source.addEventListener('message', function(e) {
      document.getElementById('data').innerHTML = e.data
    }, false)

    source.addEventListener('open', function(e) {
      document.getElementById('state').innerHTML = "Connected"
    }, false)

    source.addEventListener('error', function(e) {
      const id_state = document.getElementById('state')
      if (e.eventPhase == EventSource.CLOSED)
        source.close()
      if (e.target.readyState == EventSource.CLOSED) {
        id_state.innerHTML = "Disconnected"
      }
      else if (e.target.readyState == EventSource.CONNECTING) {
        id_state.innerHTML = "Connecting..."
      }
    }, false)
  } else {
    console.log("Your browser doesn't support SSE")
  }
  </script>
</head>
<body>
  <h1>SSE: <span id="state"></span></h1>
  <h3>Data: <span id="data"></span></h3>
</body>
</html>

In your browser, open localhost:3000 and watch the SSE countdown.

like image 122
Brent Washburne Avatar answered Sep 29 '22 14:09

Brent Washburne


I'm adding a simple implementation of SSE here. It's just one Node.js file.

You can have a look at the result here: https://glossy-ox.glitch.me/

const http = require('http');
const port = process.env.PORT || 3000;

const server = http.createServer((req, res) => {
  // Server-sent events endpoint
  if (req.url === '/events') {
    res.writeHead(200, {
      'Content-Type': 'text/event-stream',
      'Cache-Control': 'no-cache',
      ...(req.httpVersionMajor === 1 && { 'Connection': 'keep-alive' })
    });

    const refreshRate = 1000; // in milliseconds
    return setInterval(() => {
      const id = Date.now();
      const data = `Hello World ${id}`;
      const message =
        `retry: ${refreshRate}\nid:${id}\ndata: ${data}\n\n`;
      res.write(message);
    }, refreshRate);
  }

  // Client side
  res.writeHead(200, {'Content-Type': 'text/html'});
  res.end(`
    <!DOCTYPE html>
    <html lang="en" dir="ltr">
      <head>
        <meta charset="utf-8">
        <title>SSE</title>
      </head>
      <body>
        <pre id="log"></pre>
      </body>
      <script>
        var eventSource = new EventSource('/events');
        eventSource.onmessage = function(event) {
          document.getElementById('log').innerHTML += event.data + '<br>';
        };
      </script>
    </html>
  `);
});

server.listen(port);

server.on('error', (err) => {
  console.log(err);
  process.exit(1);
});

server.on('listening', () => {
  console.log(`Listening on port ${port}`);
});
like image 24
codeKonami Avatar answered Sep 29 '22 13:09

codeKonami