我正在尝试使用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来显示它。我在一项或多项中都取得了成功,但不是同时取得了成功。
我弄清楚了我所缺少的。我没有正确指定端点。对于根端点,服务器代码需要传递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必须是不同的终结点(不是root)。它必须是生成时间戳的端点。因此,在服务器中,/ 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;
});