【问题标题】:Why is the initial SSE event not handled by the onmessage listener?为什么 onmessage 监听器不处理初始 SSE 事件?
【发布时间】: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


【解决方案1】:

这是由 nginx 中的 proxy_buffering 引起的,默认情况下是“开启”的。

在 nginx 配置中关闭此功能可解决问题:

server {
# server config here...

   location / {
   # proxy config here...
   proxy_buffering off; # resolves issue
   }

}

【讨论】:

    猜你喜欢
    • 2019-11-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-02
    • 2013-10-09
    相关资源
    最近更新 更多