【问题标题】:Using server-side events (SSE) to push updates to web client using Javascript使用服务器端事件 (SSE) 将更新推送到使用 Javascript 的 Web 客户端
【发布时间】:2020-04-28 01:15:16
【问题描述】:

我正在尝试使用 Javascript 和 Node.JS 中的服务器端事件 (SSE) 将更新推送到 Web 客户端。 为了简单起见,我有一个函数会每秒生成时间:

setTimeout(function time() {
  sendEvent('time', + new Date);
  setTimeout(time, uptimeTimeout);
}, 1000);

sendEvent 函数将事件以预期的格式组合在一起并将其发送给客户端。

var clientRes;
var lastMessageId = 0;
function sendEvent(event, message) {
  message = JSON.stringify(message);
  ++lastMessageId;
  sendSSE(clientRes, lastMessageId, event, message);
}

clientRes 值来自服务器函数,用于处理来自基本 URL 的路由。

    app.use('/', function (req, res) {
        clientRes = res;
        ...
    }

我想在客户端 UI 上实现的是一个简单的页面,它显示:

>   <h1>The current time is {event.data}</h1>

我从服务器收到的最新消息数据中得出当前时间。

我创建了一个 index.html 文件让客户端监听这些服务器发送的消息:

<!DOCTYPE html>
<html>
<body>

<h1>Getting server updates</h1>
<div id="result"></div>

<script>
if(typeof(EventSource) !== "undefined") {
  console.log("Event source is supported");
  var source = new EventSource("localhost:3000");
  source.onmessage = function(event) {
    document.getElementById("result").innerHTML += "=>" + event.data + "<br>";
  };
} else {
  console.log("Event source not supported");
  document.getElementById("result").innerHTML = "Sorry, your browser does not support server-sent events...";
}
evtSource.addEventListener("time", function(event) {
  const newElement = document.createElement("li");
  const time = JSON.parse(event.data).time;
  console.log("Time listener found time " + time);
  newElement.innerHTML = "ping at " + time;
  eventList.appendChild(newElement);
});
</script>
</body>
</html> 

如果我使用此 index.html 响应 GET 请求,我看不到任何时间消息。 也就是说,这个服务器代码不起作用:

app.use("/", function(request, response) {
    response.sendFile(__dirname + "/index.html");
    clientRes = response;
});

但是,如果我不响应 index.html 文件并允许服务器将时间戳推送到客户端,它们就会显示在浏览器中:

event: time
id: 104
data: 1587943717153

event: time
id: 105
data: 1587943727161
...

这就是我卡住的地方。 看来我已经成功地让服务器每秒推送新的时间戳。 浏览器正在查看它们并显示文本。 但是来自服务器的消息到达并没有触发监听器,消息也没有根据 index.html 进行渲染。

我看到的大多数使用 SSE 的示例都涉及 PHP 数据源。我需要服务器生成数据并提供 HTML 来显示它。 我在其中一个方面都取得了成功,但不是同时在两个方面都取得了成功。

【问题讨论】:

  • 我要指出的第一件事是,您不能将clientRes 保存在 Express 路由处理程序之外的范围内,因为这意味着每个路由都会覆盖前一个路由。所有模块范围的变量都由所有路由共享。相反,您需要从路由内部调用您的代码并将其传递给那里的res。这不是您要问的问题,但很快就会成为问题。

标签: javascript node.js server-sent-events


【解决方案1】:

我知道我错过了什么。 我没有正确指定端点。 对于根端点,服务端代码需要下发 index.html 文件。

app.use("/", function(request, response) {
    console.log("In root handler");
    response.sendFile(__dirname + "/index.html");
});

Index.html 包含创建事件源的脚本:

    var source = new EventSource("http://localhost:3000/time");

但是作为 EventSource 构造函数的输入传入的 URL 必须是不同的端点(不是根)。它必须是生成时间戳的端点。 因此,在服务器中,/time 端点的处理程序是推送数据的处理程序。

app.use('/time', function (req, res) {
      res.writeHead(200, {
        'content-type': 'text/event-stream',
        'cache-control': 'no-cache',
        'connection': 'keep-alive'
      });

      // Save the response 
      clientRes = res;
});

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-06-02
    • 1970-01-01
    • 1970-01-01
    • 2015-09-11
    • 1970-01-01
    • 2014-02-04
    • 2015-07-09
    相关资源
    最近更新 更多