使用服务器端事件(SSE)使用Javascript将更新推送到web客户端



我正在尝试在Javascript和Node中使用服务器端事件(SSE(。JS向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来显示它。我在其中一个方面取得了成功,但不是同时取得成功。

我找到了我缺少的东西。我没有正确指定端点。对于根端点,服务器代码需要传递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;
});

最新更新