JavaScript EventSource SSE не запускается в браузере

Я разрабатываю сервер nodejs для предоставления серверных событий для нового веб-сайта, который я разрабатываю в HTML5.

когда я telnet на сервер, он работает правильно, отправляя мне необходимые заголовки HTTP-ответов, а затем поток событий, которые я в настоящее время генерирую каждые 2 или 3 секунды, чтобы доказать, что он работает.

Я пробовал последнюю версию FireFox, Chrome и Opera, и они создают объект EventSource и подключаются к серверу nodejs OK но ни один из браузеров не генерирует никаких событий, включая onopen, onmessage и onerror.

однако, если я остановлю свой сервер nodejs, завершив соединение из браузеров, они все внезапно отправят все сообщения, и все мои события будут показаны. Затем браузеры пытаются подключиться к серверу в соответствии со спецификацией.

Я размещаю все на веб-сервере. в локальных файлах ничего не работает.

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

пример реализации сервера

  var http = require('http');
  var requests = [];

  var server = http.Server(function(req, res) {
    var clientIP = req.socket.remoteAddress;
    var clientPort = req.socket.remotePort;

    res.on('close', function() {
      console.log("client " + clientIP + ":" + clientPort + " died");

      for(var i=requests.length -1; i>=0; i--) {
        if ((requests[i].ip == clientIP) && (requests[i].port == clientPort)) {
          requests.splice(i, 1);
        }
      }
    });

    res.writeHead(200, {
      'Content-Type': 'text/event-stream', 
      'Access-Control-Allow-Origin': '*', 
      'Cache-Control': 'no-cache', 
      'Connection': 'keep-alive'});

    requests.push({ip:clientIP, port:clientPort, res:res});

    res.write(": connected.nn");
  });

  server.listen(8080);

  setInterval(function test() {
    broadcast('poll', "test message");
  }, 2000);

function broadcast(rtype, msg) {
  var lines = msg.split("n");

  for(var i=requests.length -1; i>=0; i--) {
    requests[i].res.write("event: " + rtype + "n");
    for(var j=0; j<lines.length; j++) {
      if (lines[j]) {
        requests[i].res.write("data: " + lines[j] + "n");
      }
    }
    requests[i].res.write("n");
  }
}

пример html-страницы

<!DOCTYPE html>
<html>
  <head>
    <title>SSE Test</title>
    <meta charset="utf-8" />
    <script language="JavaScript">
      function init() {
        if(typeof(EventSource)!=="undefined") {
          var log = document.getElementById('log');
          if (log) {
            log.innerHTML = "EventSource() testing begins..<br>";
          }

          var svrEvents = new EventSource('/sse');

          svrEvents.onopen = function() {
            connectionOpen(true);
          }

          svrEvents.onerror = function() {
            connectionOpen(false);
          }

          svrEvents.addEventListener('poll', displayPoll, false);             // display multi choice and send back answer

          svrEvents.onmessage = function(event) {
              var log = document.getElementById('log');
              if (log) {
                log.innerHTML += 'message: ' + event.data + "<br>";
              }
            // absorb any other messages
          }
        } else {
          var log = document.getElementById('log');
          if (log) {
            log.innerHTML = "EventSource() not supported<br>";
          }
        }
      }

      function connectionOpen(status) {
          var log = document.getElementById('log');
          if (log) {
            log.innerHTML += 'connected: ' + status + "<br>";
          }
      }

      function displayPoll(event) {
        var html = event.data;
          var log = document.getElementById('log');
          if (log) {
            log.innerHTML += 'poll: ' + html + "<br>";
          }
      }
    </script>
  </head>
  <body onLoad="init()">
    <div id="log">testing...</div>
  </body>
</html>

эти примеры являются основными, но такого же разнообразия, как и все другие демо я видел в книгах и в интернете. EventSource работает только в том случае, если я завершаю клиентское соединение или завершаю сервер, но это будет опрос вместо SSE и I особенно хочу использовать SSE.

интересно, демо, такие как thouse от html5rock также, похоже, не совсем работает, как ожидалось, когда я использую их в интернете..

3 ответов


взломал его! :)

благодаря некоторой помощи от Тома Керстен кто помог мне с тестированием. Оказывается, проблема не в коде.

будьте осторожны.. если ваш клиент использует какое-либо антивирусное программное обеспечение, которое перехватывает веб-запросы, это может вызвать проблемы здесь. В этом случае Sophos Endpoint Security, которая обеспечивает антивирусную защиту корпоративного уровня и защиту брандмауэра, имеет функцию web protection. В рамках этой функции есть возможность сканировать загрузки; кажется, что подключение ГСП рассматривается как скачать и тем самым не выпустили в браузере до закрытия подключения и трансляция полученных для сканирования. Отключение этой опции устраняет проблему. Я подала отчет об ошибке, но и другие антивирусные системы могут сделать то же самое.

спасибо за ваши предложения и помочь каждому :)


http://www.w3.org/TR/eventsource/#parsing-an-event-stream

Так как для таких ресурсов установлены подключения к удаленным серверам ожидаемый длительный срок службы, бас должен обеспечить, чтобы используется буферизация. В частности, в то время как буферизация строк строками определенный для того чтобы закончить с одиночным символом (LF) питания линии U+000A безопасен, блочная буферизация или буферизация строк c различными ожидаемыми концами строк может вызвать задержки в событии отправка.

попробуйте сыграть с окончаниями строк ("\r\n" вместо "\n").

http://www.w3.org/TR/eventsource/#notes

авторы также предупреждены, что HTTP-фрагментация может иметь неожиданные негативные последствия для надежности настоящего Протокола. Где можно, chunking должен быть отключен для обслуживания потоков событий, если скорость сообщений достаточно высоко, чтобы это не имело значения.


Я изменил ваш серверный скрипт, который "кажется" частично работает для Chrome.
Но разрыв соединения для каждой трансляции 2 и только 1 может быть показан на клиенте.

Firefox работает для 1-й трансляции и останавливается на этой ошибке:

ошибка: соединение с /sse было прервано во время загрузки страницы.

и Chrome попытается снова подключиться и получить 3-ю трансляцию.

Я думаю, что это связано с настройкой брандмауэра тоже но не могу объяснить, почему где-то работает.

Примечание: для прослушивателя событий ответа (строка 10), "закрыть" и "конец" имеют другой результат,
Вы можете попробовать, и мой результат [close: 1 success / 2 broadcast] & [end: 1 success/8 broadcast]

var http = require('http'), fs = require('fs'), requests = [];

var server = http.Server(function(req, res) {
  var clientIP = req.socket.remoteAddress;
  var clientPort = req.socket.remotePort;
  if (req.url == '/sse') {
    var allClient="";for(var i=0;i<requests.length;i++){allClient+=requests[i].ip+":"+requests[i].port+";";}
    if(allClient.indexOf(clientIP+":"+clientPort)<0){
      requests.push({ip:clientIP, port:clientPort, res:res});
      res.on('close', function() {
        console.log("client " + clientIP + ":" + clientPort + " died");
        for(var i=requests.length -1; i>=0; i--) {
          if ((requests[i].ip == clientIP) && (requests[i].port == clientPort)) {
            requests.splice(i, 1);
          }
        }
      });
    }
  }else{
    res.writeHead(200, {'Content-Type': 'text/html'});
    res.write(fs.readFileSync('./test.html'));
    res.end();
  }
});
server.listen(80);

setInterval(function test() {
  broadcast('poll', "test message");
}, 500);

var broadcastCount=0;
 function broadcast(rtype, msg) {
    if(!requests.length)return;
    broadcastCount++;
    var lines = msg.split("\n");
    for(var i = requests.length - 1; i >= 0; i--) {
        requests[i].res.writeHead(200, {
            'Content-Type': 'text/event-stream',
            'Cache-Control': 'no-cache',
            'Connection': 'keep-alive'
        });
        requests[i].res.write("event: " + rtype + "\n");
        for(var j = 0; j < lines.length; j++) {
            if(lines[j]) {
                requests[i].res.write("data: " + lines[j] + "\n");
            }
        }
        requests[i].res.write("data: Count\: " + broadcastCount + "\n");
        requests[i].res.write("\n");
    }
    console.log("Broadcasted " + broadcastCount + " times to " + requests.length + " user(s).");
 }