Node.JS События, отправленные сервером: маршрут продолжает работать после res.end (), что приводит к ошибке ERR_STREAM_WRITE_AFTER_END - PullRequest
1 голос
/ 18 января 2020

Я начинаю работу с событиями отправки сервера (SSE), поскольку моему веб-приложению требуется получать обновления с сервера в режиме реального времени. Он не требует отправки чего-либо на сервер, поэтому SSE был выбран через Websockets.

После прочтения некоторых примеров у меня есть следующий код:

На моем сервере в . / Src / маршрутизаторы / mainRouter. js У меня есть:

router.get('/updates', (req, res) => {
    res.writeHead(200, {
        'Content-Type': 'text/event-stream',
        'Cache-Control': 'no-cache',
        'Connection': 'keep-alive'
    })

    // Listens for 'event' and sends an 'Event triggered!' message to client when its heard.
    eventEmitter.addListener('event', () => {
        console.log('Event triggered! Sending response.')
        res.write('data: Event triggered!\n\n')
    })

    req.on('close', () => {
        console.log('Connection to client closed.')
        res.end()
    })
})

module.exports = router

На моем клиенте в . / App / index. js У меня есть :

const source = new EventSource('/updates')

source.onmessage = (e) => {
    console.log(e)
}

У меня есть 2 проблемы:

  1. Как только я открываю соединение со стороны клиента, а затем закрываю соединение (закрывая вкладка), событие 'close' запускается дважды, в результате чего блок кода в req.on('close') запускается дважды. Я не уверен, почему это происходит. Мой console на стороне сервера выглядит следующим образом:

    Event triggered! Sending response.
    Connection to client closed.
    Connection to client closed.
    
  2. Что еще более важно, хотя req.end() вызывается, маршрутизатор продолжает прослушивать события на этом канале и пытается отправьте ответы по этому каналу, что приведет к ошибке ERR_STREAM_WRITE_AFTER_END и сбою сервера. Таким образом, окончательный вывод консоли выглядит так:

    Event triggered! Sending response. // First event triggers.
    Connection to client closed. // 'close' event fires.
    Connection to client closed. // 'close' event fires a second time (not sure why).
    Event triggered! Sending response. // Router continues listening for 'event' and sends another response although res.end() was called earlier
    events.js:187
          throw er; // Unhandled 'error' event
          ^
    
    Error [ERR_STREAM_WRITE_AFTER_END]: write after end
    

1 Ответ

2 голосов
/ 18 января 2020

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

router.get('/updates', (req, res) => {
    res.writeHead(200, {
        'Content-Type': 'text/event-stream',
        'Cache-Control': 'no-cache',
        'Connection': 'keep-alive'
    });

    function listener(event) {
        console.log('Event triggered! Sending response.');
        res.write('data: Event triggered!\n\n');
    }

    // Listens for 'event' and sends an 'Event triggered!' message to client when its heard.
    eventEmitter.addListener('event', listener);

    req.on('close', () => {
        // remove listener so it won't try to write to this stream any more
        eventEmitter.removeListener('event', listener);
        console.log('Connection to client closed.');
        res.end();
    });
});

module.exports = router;

К вашему сведению, я не думаю, что вам нужно res.end(), когда вы уже получили событие close. Вы бы использовали res.send(), если бы вы в одностороннем порядке пытались закрыть соединение с сервера, но если оно уже закрывается, я не думаю, что вам это нужно, и ни один из примеров кода, которые я видел, не использовал его таким образом.

Интересно, возможно ли, что ваш res.end() также является причиной того, что вы получаете два close события. Попробуйте удалить его.

...