Use Koa for Server-Sent Events

1.4k Views Asked by At

After having implemented SSE with Express I wanted to do the same with Koa like so:

const Koa = require('koa');
const Router = require('koa-router');

const app = new Koa();
const router = new Router();

router.get('/stream', (ctx, next) => {
  ctx.set({
    'Access-Control-Allow-Origin': '*',
    'Content-Type': 'text/event-stream',
    'Cache-Control': 'no-cache',
    Connection: 'Keep-Alive',
  });

  const id = new Date().toLocaleTimeString();
  ctx.res.write(`id: ${id}'\n`);
  ctx.res.write(`data: CONNECTION ESTABLISHED)}\n\n`);
  next();
});

app.use(router.routes());

app.listen(8080, () => {
  console.log('Listening on port 8080');
});

And for my client, in a React component's constructor:

constructor(props) {
    super(props);

    this.state = {
      source: new EventSource("http://localhost:8080/stream"),
    };
}

But for some reason, I received the following error message client-side:

Firefox can’t establish a connection to the server at http://localhost:8080/stream.

Even though my client's request to /stream does go through (but no answer is sent back).

What could be causing this problem with the SSE connection?

I have a Koa server listening on a given port, a route to catch the initial GET request with the correct header data and yet it fails.

1

There are 1 best solutions below

0
On

A major problem here is that Koa will 'end' the HTTP response as soon as all middleware have run.

This happens immediately after the function ends, of if the function returns a promise, when the promise has resolved. To keep a connection open and circumvent Koa's response handling, you need to make sure that the function 'never ends', and the best way to do that is to simply return a promise that does not resolve.

You're effectively taking over the response handling and stopping Koa from doing so. At this point you can start doing stuff with the socket.

I'm not sure if a more appropriate way exists to handle this in Koa, but this is how I've solved this in the past.