express.js не передает поток chunked 'text/event-stream' resposne

Я пытаюсь отправить 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) line Он корректно очищает поток, но затем возвращается к опросу событий и не передает поток ответа.

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

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

1 ответ

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

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

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();

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

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).

Другие вопросы по тегам