我正在尝试在 NodeJS 服务器和 TypeScript 前端之间设置 SSE。我的服务器代码如下所示:
let sseInterval: { [index: string]: NodeJS.Timer } = {};
this.app.get('/events/:id', (req, res) => {
const headers = {
'Content-Type': 'text/event-stream',
'Connection': 'keep-alive',
'Cache-Control': 'no-cache'
};
res.writeHead(200, headers);
const instanceId = req.params.id;
const instance = this.findInstance(instanceId);
if (!instance) {
global.logger.debug('sse closed', {metadata: {for: instanceId}})
clearInterval(sseInterval[instanceId]);
res.end();
return;
}
global.logger.debug('sse connected', {metadata: {for: instanceId, instance: instance.config()}})
res.write(`data: ${JSON.stringify(instance.all())}\n\n`);
sseInterval[instanceId] = setInterval(() => {
global.logger.debug('sse interval', {metadata: {for: instanceId}})
res.write(`data: ${JSON.stringify(instance.all())}\n\n`);
}, 1000);
req.on('close', () => {
clearInterval(sseInterval[instanceId]);
res.end();
});
});
对于前端,我使用以下代码:
const datapolling = () => {
let eventSource: EventSource = new EventSource(window.server.url + '/events/' + window.server.key);
eventSource.onopen = (event) => {
console.log('connected', event);
}
eventSource.onmessage = (event) => {
console.log('onmessage', new Date(), event);
const json = JSON.parse(event.data);
updateGUI(json);
};
eventSource.onerror = (event) => {
console.error('error', event);
setTimeout(datapolling, 500);
};
window.addEventListener('beforeunload', () => {
eventSource.close();
});
}
console.log('polling', new Date());
datapolling();
问题是,前端每 3000 毫秒才接收一次事件,但一次会接收 3-4 个事件。如果我将后端间隔设置为 500 毫秒,则我每 1500 毫秒获取一次前端事件,再次一次 3-4 个。
有什么明显的我做错的事情吗?
Basic implementation of SSE (server sent events)
:从服务器单向发送事件:
this.router.get("/sse", async (req: Request, res: Response) => {
// SSE Headers
res.setHeader("Content-Type", "text/event-stream");
res.setHeader("Access-Control-Allow-Origin", "*");
res.flushHeaders();
//SSE
const sseId = new Date().toDateString();
this.writeEvent(res, sseId, `START`);
this.writeEvent(res, sseId, `0`);
this.writeEvent(res, sseId, `1`);
setTimeout(()=>{
this.writeEvent(res, sseId, `END`);
},2000);
//On close event end SSE event emission
res.on("close", () => {
res.emit("close");
res.end();
});
});
const source = new EventSource("http://localhost:8000/api/sse");
source.onopen = () => {
// console.log("SSE opened!");
};
source.onmessage = (e: MessageEvent) => {
// In my case I am using alert to see data
// alert(e.data);
const p = e?.data;
//Send close event to sse open channel
if (t == "END") {
source.close();
}
};
source.onerror = (e: Event) => {
console.error("Error: ", e);
};