Node.JS Server Sent Events: Route continues to run after res.end() resulting in ERR_STREAM_WRITE_AFTER_END error

守給你的承諾、 提交于 2020-01-22 02:21:58

问题


I am getting started with Server Sent Events (SSE) since my web app requires receiving real time updates from the server. It does not require sending anything to the server, therefore SSE was chosen over Websockets.

After reading through some examples, I have the following code:

On my server, in ./src/routers/mainRouter.js I have:

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

On my client, in ./app/index.js I have:

const source = new EventSource('/updates')

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

There are 2 issues I am having:

  1. Once I open a connection from the client side and then close the connection (by closing the tab), the 'close' event fires twice resulting in the code block within req.on('close') running twice. I am not sure why this happens. My console on the server side looks like follows:

    Event triggered! Sending response.
    Connection to client closed.
    Connection to client closed.
    
  2. More importantly, although req.end() is called, the router still keeps listening for events on that channel and tries to send responses down that channel resulting in a ERR_STREAM_WRITE_AFTER_END error and the server crashing. So the final console output looks like:

    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:


When the stream closes, you need to remove your event listener so you won't try to write to the stream again. That could be done like this:

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;

FYI, I don't think you need the res.end() when you've already received the close event. You would use res.send() if you were unilaterally trying to close the connection from the server, but if it's already closing, I don't think you need it and none of the code examples I've seen use it this way.

I wonder if it's possible that your res.end() is also why you're getting two close events. Try removing it.



来源:https://stackoverflow.com/questions/59797523/node-js-server-sent-events-route-continues-to-run-after-res-end-resulting-in

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!