我正在尝试在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;
});