Использование событий на стороне сервера (SSE) для обновления веб-клиента pu sh с использованием Javascript - PullRequest
0 голосов
/ 27 апреля 2020

Я пытаюсь использовать серверные события (SSE) в Javascript и Node.JS до pu sh обновлений для веб-клиента. Для простоты у меня есть функция, которая генерирует время каждую секунду:

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;
        ...
    }

То, чего я хочу добиться в пользовательском интерфейсе клиента, - это простая страница, которая показывает:

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

где я получаю текущее время из последних данных сообщений, полученных с сервера.

Я создал индексный файл. 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> 

Если я отвечаю на запрос GET с этим индексом. html, я не вижу ни одного сообщения времени. То есть этот код сервера не работает:

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

Однако, если я не отвечаю с файлом index. html и разрешаю серверу выдавать клиенту метки времени sh, они показать в браузере:

event: time
id: 104
data: 1587943717153

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

Вот где я застрял. Похоже, что я успешно получаю сервер с пу sh новых отметок времени каждую секунду. И браузер видит их и отображает текст. Но поступление сообщения с сервера не вызывает слушателя, и сообщение не обрабатывается на основе индекса. html.

Большинство примеров, которые я видел для использования SSE, включают PHP источник данных. Мне нужно, чтобы сервер генерировал данные и предоставлял HTML для их отображения. Я был успешным в том или ином, но не в обоих одновременно.

1 Ответ

1 голос
/ 27 апреля 2020

Я понял, чего мне не хватало. Я не правильно указал конечные точки. Для конечной точки root код сервера должен доставлять индекс. html файл.

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

Индекс. html содержит скрипт, который создает источник события:

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

Но URL-адрес, который передается в качестве входных данных для конструктора EventSource, должен быть другой конечной точкой (не 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;
});
...