Express.js не передает ответ на фрагментированный «текст/поток событий»

Я пытаюсь отправить ответ SSE text/event-stream из конечной точки express.js. Мой обработчик маршрута выглядит так:

function openSSE(req, res) {
  res.writeHead(200, {
    'Content-Type': 'text/event-stream; charset=UTF-8',
    'Cache-Control': 'no-cache',
    'Connection': 'keep-alive',
    'Transfer-Encoding': 'chunked'
  });

  // support the polyfill
  if (req.headers['x-requested-with'] == 'XMLHttpRequest') {
    res.xhr = null;
  }

  res.write(':' + Array(2049).join('\t') + '\n'); //2kb padding for IE
  res.write('id: '+ lastID +'\n');
  res.write('retry: 2000\n');
  res.write('data: cool connection\n\n');

  console.log("connection added");
  connections.push(res);
}

Позже я звоню:

function sendSSE(res, message){
    res.write(message);
    if (res.hasOwnProperty('xhr')) {
        clearTimeout(res.xhr);
        res.xhr = setTimeout(function () {
          res.end();
          removeConnection(res);
        }, 250);
    }
}

Мой браузер делает и удерживает запрос: введите здесь описание изображения

Ни один из ответов не передается в браузер. Ни одно из моих событий не запущено. Если я убью сервер express.js. Ответ внезапно истощается, и каждое событие сразу попадает в браузер. введите здесь описание изображения

Если я обновлю свой код, чтобы добавить res.end() после строки res.write(message), он правильно очищает поток, однако затем возвращается к опросу событий и не передает ответ. введите здесь описание изображения

Я попытался добавить дополнение к заголовку ответа, например res.write(':' + Array(2049).join('\t') + '\n');, как я видел из другого сообщения SO, которое может заставить браузер истощить ответ.

Я подозреваю, что это проблема с express.js, потому что я ранее использовал этот код с собственным сервером http узлов, и он работал правильно. Поэтому мне интересно, есть ли способ обойти экспресс-оболочку объекта ответа.


person kevzettler    schedule 22.04.2015    source источник
comment
Я считаю, что это проблема Chrome. Я сделал это буквально 2 дня назад. Поменял Content-Type на text/json и он волшебным образом заработал.   -  person Randy    schedule 22.04.2015
comment
Когда я вернусь домой, я попробую text/event-stream код, который, как я знаю, работает.   -  person Randy    schedule 22.04.2015
comment
Я пробовал в firefox и видел такое же поведение. Я попробую text/json, и если это поможет.   -  person kevzettler    schedule 22.04.2015
comment
@Randy изменил мой Content-Type (для ответа) на text/json. ничего не сделал   -  person kevzettler    schedule 22.04.2015
comment
такая же проблема, вы решили эту проблему? Как ты это делаешь? спасибо.   -  person vikingmute    schedule 04.12.2015
comment
Да. Для всех, кто видит эту проблему. Для меня это была проблема с моей конфигурацией nginx. Там мы восходящие правила не применяются к моему нисходящему маршруту.   -  person kevzettler    schedule 06.12.2015
comment
@kevzettler эй, я использую простой экспресс-сервер и обнаружил ту же проблему. когда я делаю curl /endpoint в командной строке, он работает нормально, но когда я открываю SSE в моем клиенте с помощью new EventSource(), возникает точно такая же проблема, как вы описываете, есть идеи по этому поводу? Спасибо   -  person vikingmute    schedule 08.12.2015
comment
@vikingmute все, что я могу сказать, если вы находитесь за прокси или брандмауэром, таким как nginx, убедитесь, что все перенаправлено правильно   -  person kevzettler    schedule 09.12.2015


Ответы (2)


Это код, который я работаю в своем проекте.

Сторона сервера:

router.get('/listen', function (req, res) {
    res.header('transfer-encoding', 'chunked');
    res.set('Content-Type', 'text/json');

    var callback = function (data) {
        console.log('data');
        res.write(JSON.stringify(data));
    };

    //Event listener which calls calback.
    dbdriver.listener.on(name, callback);

    res.socket.on('end', function () {
        //Removes the listener on socket end
        dbdriver.listener.removeListener(name, callback);
    });
});

Сторона клиента:

xhr = new XMLHttpRequest();
xhr.open("GET", '/listen', true);
xhr.onprogress = function () {
    //responseText contains ALL the data received
    console.log("PROGRESS:", xhr.responseText)
};
xhr.send();
person Randy    schedule 22.04.2015
comment
вы можете посмотреть здесь, пожалуйста, title="ответ источника событий sockjs имеет текстовый HTML-код типа mime, который не является текстовым eve"> stackoverflow.com/questions/32506980/ - person VB_; 10.09.2015

Я тоже боролся с этим, поэтому после некоторого просмотра и чтения я решил эту проблему, установив дополнительный заголовок для объекта ответа:

res.writeHead(200, {
  "Content-Type": "text/event-stream",
  "Cache-Control": "no-cache",
  "Content-Encoding": "none"
});

Короче говоря, когда EventSource ведет переговоры с сервером, он отправляет заголовок Accept-Encoding: gzip, deflate, br, который заставляет express отвечать заголовком Content-Encoding: gzip. Таким образом, есть два решения этой проблемы: первое — добавить заголовок Content-Encoding: none к ответу, а второе — сжать ваш ответ (gzip).

person Zoti    schedule 30.10.2019