我已经使用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的方式有关吗?
答案 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:如果代码告诉我有任何错误,我会尽快写出,我将予以纠正。