Node.JS Server发送事件:res.end()之后,路由继续运行,导致ERR_STREAM_WRITE_AFTER_END错误 [英] Node.JS Server Sent Events: Route continues to run after res.end() resulting in ERR_STREAM_WRITE_AFTER_END error

查看:1215
本文介绍了Node.JS Server发送事件:res.end()之后,路由继续运行,导致ERR_STREAM_WRITE_AFTER_END错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

由于我的Web应用程序需要从服务器接收实时更新,因此我开始使用服务器发送事件"(SSE).它不需要向服务器发送任何内容,因此通过Websockets选择了SSE.

在阅读了一些示例之后,我有以下代码:

在服务器上的./src/routers/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
    

解决方案

流关闭时,您需要删除事件侦听器,以免再次尝试写入流.可以这样完成:

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;

仅供参考,当您已经收到close事件时,我认为您不需要res.end().如果您单方面尝试从服务器关闭连接,则可以使用res.send(),但是如果已经关闭,则我认为您不需要它,而且我见过的代码示例都没有以这种方式使用它. >

我想知道您的res.end()是否也可能是为什么您会收到两个close事件的原因.尝试将其删除.

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
    

解决方案

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.

这篇关于Node.JS Server发送事件:res.end()之后,路由继续运行,导致ERR_STREAM_WRITE_AFTER_END错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆