我已经使用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的方式有关吗?
我正在为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,但我会试一试。我能够正确地建立连接,进行这一小改动。
这有点太晚了,但我会用Koa写下我的经验。
ctx.respond = false
绕过koa响应机制。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:如果代码有任何问题告诉我,我会抓紧写这个,我会纠正它。