问题
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:
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 withinreq.on('close')
running twice. I am not sure why this happens. Myconsole
on the server side looks like follows:Event triggered! Sending response. Connection to client closed. Connection to client closed.
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 aERR_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