Koa SSE连接重新连接

问题描述 投票:1回答:2

我已经使用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方法在后端发送的答案。

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

并且我的前端错误监听器每次都会捕获一个CONNECTING事件。

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

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

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

server-sent-events koa koa2
2个回答
0
投票

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

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

根据我自己的测试,由于从服务器发回的数据,EventSource发出错误。根据docs,具有除“text / event-stream”之外的Content-Type的200响应将导致失败。

在您的示例中,您已将响应声明为“text / event-stream”并将字符串传递给ctx.res.write方法。虽然这看起来是正确的,并且实际上在使用类似的代码和Express时起作用,但似乎它在Koa中不起作用。但是,如果您更改正在写入流的响应的“数据”,例如此示例here,您将发现连接正确建立。

也许尝试以下方法:

//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,但我会试一试。我能够正确地建立连接,进行这一小改动。


0
投票

这有点太晚了,但我会用Koa写下我的经验。

  • 首先直接使用ctx.res并不是很受Koa赞赏,如果你还想使用它,一定要把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:如果代码有任何问题告诉我,我会抓紧写这个,我会纠正它。

© www.soinside.com 2019 - 2024. All rights reserved.