Событие, отправленное сервером: клиент не получает ответа от сервера

Я пытаюсь использовать события, отправленные сервером, чтобы моя веб-страница могла периодически обновлять время с моего сервера. Проблема в том, что мой клиент может взаимодействовать с моим сервером, однако ответ с моего сервера не доходит до моего клиента? По сути, когда я открываю свой html-файл с помощью firefox, я знаю, что мой сервер получает запрос, а затем начинает отправлять ответы, но на моей веб-странице ничего не отображается... Не совсем уверен, в чем проблема. Помощь приветствуется!

Вот мой клиентский код:

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8" />
</head>
  <script>
     function init(){ 
      if(typeof(EventSource)!=="undefined"){
        var source = new EventSource('localhost');
        source.onmessage = function(e) {
        document.body.innerHTML += e.data + '<br>';
        };
      }
      else{
        document.body.innerHTML = "Sorry, your browser does not support server-sent events...";
      }
    }
  </script>
<body onload="init()">
</body>
</html>

Вот код моего сервера (node.js):

var http = require('http');
var sys = require('sys');
var fs = require('fs');

http.createServer(function(req, res) {

  if (req.headers.accept && req.headers.accept == 'text/event-stream') {
      sendSSE(req, res);
}).listen(80, "127.0.0.1");

function sendSSE(req, res) {
  res.writeHead(200, {
    'Content-Type': 'text/event-stream',
    'Cache-Control': 'no-cache',
    'Connection': 'keep-alive'
  });

  var id = (new Date()).toLocaleTimeString();

  // Sends a SSE every 5 seconds on a single connection.
  setInterval(function() {
    constructSSE(res, id, (new Date()).toLocaleTimeString());
  }, 5000);
}

function constructSSE(res, id, data) {
  res.write('id: ' + id + '\n');
  res.write("data: " + data + '\n\n');
  }

person user2547593    schedule 03.07.2013    source источник


Ответы (2)


Вам нужно добавить в

res.end();

где-нибудь и удалите «setInterval». Однако похоже, что вы пытаетесь сохранить соединение, и в этом случае вам необходимо значительно изменить свой код. Посмотрите на модуль «net», который больше предназначен для «постоянного» интерактивного типа соединения.

http://nodejs.org/api/net.html#net_net

Модуль http предназначен для конечного, обмена данными, типа запросов. Вы пытаетесь заставить его делать то, для чего он не предназначен.

/*jshint node:true */
var http = require('http');

http.createServer(function (req, res) {
    'use strict';
    console.log('GOOD request recieved');
    res.write('hi there');
    res.end();
    console.log('GOOD end sent');
}).listen(8888);

http.createServer(function (req, res) {
    'use strict';
    console.log('BAD request received');
    res.write('hi there');
    console.log('BAD response wrote not ending');
}).listen(8889);

Рассмотрим два сервера, которые у меня есть выше. Если вы пропингуете их обоих с помощью клиентского кода узла, вы увидите, что данные приходят к обоим, и вы должны увидеть фрагменты по мере их отправки. Однако, если вы попытаетесь пропинговать 8889 с помощью браузера, веб-страница никогда не отобразится, потому что событие завершения никогда не отправляется. Браузеры зависят от этого, чтобы знать, что весь контент был получен. Если ваш клиентский код работает в браузере, это может повлиять на ситуацию. Сначала попытайтесь использовать простой клиентский код NodeJS на своем сервере и убедитесь, что данные отправляются так, как вы ожидаете. Затем поработайте над выяснением того, как браузер нарушает работу. Я предполагаю, что данные получены браузером, но он никогда ничего с ними не делает, а сидит и ждет, чтобы распределить их для этого «конечного» события, точно так же, как веб-страница сервера 8889 никогда не отображается... это считает, что есть больше данных, чтобы ждать.

Пример кода клиента:

var options = {
    hostname: '127.0.0.1',
    method: 'GET'
};

options.port = 8888;

http.request(options, function (res) {
    'use strict';

    console.log('GOOD Pinged server');

    res.on('data', function (chunk) {
        console.log('GOOD data chunk:' + chunk);
    });

    res.on('end', function () {
        console.log('GOOD end event recieved');
    });
}).end();

options.port = 8889;

http.request(options, function (res) {
    'use strict';
    console.log('BAD Pinged server');

    res.on('data', function (chunk) {
        console.log('BAD data chunk:' + chunk);
    });

    res.on('end', function () {
        console.log('BAD end event recieved');
    });
}).end();
person ChrisCM    schedule 03.07.2013
comment
О, я вижу, спасибо. Думаю, тогда мне нужно будет переделать код. Однако один вопрос: когда я помещаю html-файл в тот же каталог, что и мой файл node.js, запускаю свой сервер и перехожу на localhost/index.html в firefox. Веб-страница работает как положено. Вы знаете, почему это так? - person user2547593; 03.07.2013
comment
Моя рекомендация заключалась бы в том, что, пока вы занимаетесь локальной разработкой, настройте свою программу на прослушивание какого-то бессмысленного порта, чтобы вы точно знали, что другие службы не прослушивают этот порт. Предотвращает случайную чушь, подобную этой, от путаницы в процессе отладки. А еще лучше используйте утилиту аргументов командной строки, чтобы вы могли указать порт при запуске вашего процесса :) - person ChrisCM; 03.07.2013
comment
хм, но вернемся к первоначальному вопросу: я знаю, что мой сервер отвечает и пишет их. Однако я предполагаю, что мой клиент никогда их не получит, иначе я бы получил контент. Будет ли это ошибкой моего кода сервера или клиента? Извините за все эти вопросы и спасибо за быстрые ответы. - person user2547593; 03.07.2013

Модуль http в узле отлично работает для событий, отправленных сервером, и большая часть демонстрационного кода для Node SSE использует его. Но вы должны быть осторожны с некоторыми подводными камнями.

Меня укусила включенная компрессия. Решение состоит в том, чтобы добавить res.flush() после последних res.write() каждого сообщения данных. Поскольку это легко исправить, я бы сначала попробовал это, прежде чем переписывать с использованием другого модуля.

person Trott    schedule 30.09.2014