Koa SSE连接重新连接

时间:2018-11-14 08:21:29

标签: server-sent-events koa koa2

我已经使用Koa建立了SSE连接,如下所示:

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

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

// Sets up the HTTP header and sends a message via SSE
function writeSSE(ctx, message) {
  ctx.res.writeHead(200, {
    'Content-Type': 'text/event-stream',
    'Cache-Control': 'no-cache',
    Connection: 'keep-alive',
    'Access-Control-Allow-Origin': '*',
  });

  ctx.res.write(`id: 01\n`);
  ctx.res.write(`data: ${message}\n\n`);
}

// Router Middleware
router.get('/stream', (ctx, next) => {
  writeSSE(ctx, 'Stream reached.');
});

app.use(router.routes()).use(router.allowedMethods());

app.listen(8080);

我的React组件在哪里像这样开始连接:

new EventSource("http://localhost:8080/stream")

该组件随后在后端接收writeSSE方法发送的答案。

但是由于某种原因,每3秒钟左右就会到达一次/stream端点,就像重新建立连接一样。

我前端的错误侦听器每次都会捕获CONNECTING事件。

this.state.source.onerror = (e) => {         
   if (e.target.readyState == EventSource.CONNECTING) {
     console.log("Connecting...");
   }
};

在后端,ctx.response等于{ status: 404, message: 'Not Found', header: {} }

有人知道这个问题的起因吗?它与我使用Koa的方式有关吗?

2 个答案:

答案 0 :(得分:0)

我正在为SSE实现基于Koa的服务器。我一直遇到相同的问题,这是我的想法/有效的解决方案:

据我所知,继续调用onmessage和onerror的原因是因为客户端的EventSource对象正在发出错误事件。这导致连接断开,这导致客户端向服务器发送另一个请求以初始化流。从这里开始,该过程将无限期地重复。

根据我自己的测试,由于从服务器发送回的数据,EventSource发出错误。根据{{​​3}},如果200响应的Content-Type为“文本/事件流”以外的内容,则会导致失败。

在您的示例中,您已将响应声明为“文本/事件流”,并将字符串传递到ctx.res.write方法中。尽管这看起来是正确的,并且实际上在使用可比较的代码和Express时可以使用,但似乎在Koa中不起作用。但是,如果更改了要写入流响应的“数据”(例如本示例docs),则会发现连接正确建立。

也许尝试以下操作:

//require Passthrough
const PassThrough = require('stream').PassThrough;

//then, in your writeSSE function, try this:
let stream = new PassThrough();
stream.write(`data: ${message}\n\n`);
ctx.res.write(stream);

我不确定此更改为何有效。我最好的猜测是,关于Koa的ctx对象,有一些东西无法将纯字符串或模板文字视为有效的文本/事件流数据,但这完全是假设(这引出了它为什么在Express中工作的问题,但希望更博学的人可以为我们两个人回答这个问题。根据我在网上发布的其他摘要所看到的,流式方法是Koa中采用的一种方法。

我不确定您的结果如何,因为您似乎使用的Koa版本可能与我使用的版本不同,但我会试一试。进行了很小的更改,我就能正确建立我的连接。

答案 1 :(得分:0)

这有点为时已晚,但是我将使用Koa写下我在sse方面的经验。

  • 首先,Koa不怎么直接使用ctx.res,如果您仍要使用它,请确保使用ctx.respond = false绕过koa响应机制。

  • 以我的经验,流是在Koa中使用SSE的最佳方法,您可以执行以下操作:

const stream = require('stream');
const koa = require('koa');


const app = new koa();

app.use(async ctx => {
  ctx.set({
    'Content-Type': 'text/event-stream',
    'Cache-Control': 'no-cache',
    'Connection': 'keep-alive'
    });
  ctx.status = 200;
  const stream = new stream.PassThrough()
  ctx.body = stream; // here koa will pipe the ctx.res to stream and end the ctx.res when ever the stream ends.
  let counter = 5;
  const t = setInterval(() => {
    stream.write(`data: hi from koa sse ${counter}`);
    counter--;
    if (counter === 0) {
        stream.end();
      clearInterval(t);
    }
  }, 1000);
});

希望这对任何人都可以在koa上玩SSE有所帮助。

PS:如果代码告诉我有任何错误,我会尽快写出,我将予以纠正。