【发布时间】:2020-06-30 15:25:00
【问题描述】:
在此示例中,客户端通过创建新的 EventSource 连接到 Node Express 服务器。服务器在初始连接时发送 SSE 事件,然后每隔 30 秒发送一次。问题是客户端的 onmessage 处理程序不是由连接时发送的初始 SSE 事件触发,而是由所有后续事件触发。如果我在建立连接后立即停止服务器,这实际上会在客户端触发一个事件,表明数据实际上是在没有提前处理的情况下收到的(或者初始 res.write 仅由服务器触发关机):
服务器:
let data = {mydata: 123};
function eventsHandler(req, res, next) {
const headers = {
"Content-Type": "text/event-stream",
Connection: "keep-alive",
"Cache-Control": "no-cache",
};
res.writeHead(200, headers);
// After client opens connection we send data string, but client doesn't handle this correctly
// Event is only triggered on client if I stop the server after sending this message
res.write(`data: ${JSON.stringify(data)}\n\n`);
console.log("sent SSE");
const clientId = Date.now();
console.log(clientId, " connected");
const newClient = {
id: clientId,
res,
};
clients.push(newClient);
req.on("close", () => {
console.log(`${clientId} Connection closed`);
clients = clients.filter((c) => c.id !== clientId);
});
}
// these events are received and handled correctly on client
function sendEventsToAll(datadict) {
clients.forEach((c) => c.res.write(`data: ${JSON.stringify(datadict)}\n\n`));
}
// Route to open SSE connection
app.get("/events", eventsHandler);
// Loop to send SSE every 30 seconds - these are all received and handled correctly
async function wait() {
sendEventsToAll(data);
setTimeout(wait, 30000);
}
wait();
浏览器:
const events = new EventSource(url)
// This handles every SSE event except the one that is written immediately upon connection
// If I stop the server after connection, this will trigger and reveal the data was received but not handled
events.onmessage = event => {
const newData = JSON.parse(event.data)
console.log("newData", newData)
}
编辑:我还应该添加我正在使用 nginx 作为反向代理 - 这是否可以缓冲第一个 res.write 而不是出于某种原因立即发送它?
【问题讨论】:
-
这也可能是一些缓冲区刷新问题,所以当你写下一个时,浏览器中会出现 previous 事件。这就是为什么我要求枚举(或以其他方式区分)它们,而不是每次都发送完全相同的数据。
-
确实是缓冲区刷新问题。一旦我写下一个事件,或者当我关闭立即触发最近事件的服务器时,前一个事件就会出现在浏览器中。 Nginx 会导致这种情况吗?我可以在不结束连接的情况下强制缓冲区刷新吗?
-
尝试不使用 nginx 看看它是否是罪魁祸首 :-) 不过我会相当惊讶,这将是一个错误 imo。
-
感谢您让我走上正确的道路。这是由默认情况下“打开”的 nginx 中的 proxy_buffering 引起的。添加proxy_buffering关闭;到 nginx 配置似乎可以解决问题。
-
我想知道 nginx 是否可以检测到
Content-Type: text/event-stream并自动禁用它……我想我们现在可以关闭问题了。
标签: javascript node.js express nginx server-sent-events