Node.js Heroku H27客户端请求在服务器发送事件(SSE)GET事件上中断

Node.js Heroku H27客户端请求在服务器发送事件(SSE)GET事件上中断,node.js,heroku,server-sent-events,Node.js,Heroku,Server Sent Events,我有一个node.js服务器,它使用SSE向连接的客户端发送更新。偶尔,我会遇到服务器错误H27。同时,当客户端重新注册到SSE事件服务时,其他客户端请求可能会丢失 客户端GET/event请求和服务器H27错误之间经过的时间介于13秒到19:35分钟之间(在遇到的30个不同事件中)。但是GET/event请求的定时与相应的H27错误之间存在完全的相关性。 我每50秒从服务器发送一条保持活动的消息,以绕过55秒的Heroku超时限制 以下是我在Heroku日志中得到的完整警告示例: 2020-1

我有一个node.js服务器,它使用SSE向连接的客户端发送更新。偶尔,我会遇到服务器错误H27。同时,当客户端重新注册到SSE事件服务时,其他客户端请求可能会丢失

客户端GET/event请求和服务器H27错误之间经过的时间介于13秒到19:35分钟之间(在遇到的30个不同事件中)。但是GET/event请求的定时与相应的H27错误之间存在完全的相关性。 我每50秒从服务器发送一条保持活动的消息,以绕过55秒的Heroku超时限制

以下是我在Heroku日志中得到的完整警告示例: 2020-10-17T08:49:04.525770+00:00 heroku[路由器]:sock=client at=warning code=H27 desc=“client Request Interrupted”method=GET path=“/event”host=appname.herokuapp.com Request_id=c4c4c4e2fd-16ca-4292-a27b-2a70b12b16fa fwd=“77.138.167.76”dyno=web.1 connect=1ms service=9499ms status=499 bytes=protocol=https

这是由以下GET请求导致的: 2020-10-17T08:48:55.027638+00:00应用程序[网站1]:客户端8已注册

你知道我怎样才能克服这个问题吗?我的问题是,我的应用程序严重依赖于SSE,如果我现在必须切换到另一种机制(例如套接字),这将需要相当大的努力

编辑 经过进一步调查,这似乎是由于客户端无法保持与Heroku服务器上的服务器发送事件路由的连接。虽然它可以建立第一个连接,但无法保持连接。我怀疑这与Heroku请求超时和Heroku处理路由的方式有关


我还没有找到这个问题的解决方案,所以请大家随意评论。

我找到了一个非常粗糙的解决方案,可以解决这个问题,因为我是这个应用程序的唯一用户

首先,一些背景。问题在于,由于某些原因,部署在Heroku上的应用程序在允许客户端成功连接到SSE路由的同时,无法检测客户端连接的状态。客户端连接后,在服务器无法检测到客户端的短时间内,服务器上会出现一个
code=H27 desc=“client Request Interrupted”
错误,这表明客户端连接已关闭。由于它认为客户端连接已关闭,因此自然会触发
close
事件,导致执行SSE路由内
req.close
块中的代码

在我的开发环境中,我的SSE路由配置如下:

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

    res.write('\n')

    // eventEmitted listeners are added for each connected client.
    const eventEmitted = (data) => {
        res.write(`data: ${JSON.stringify(data)}\n\n`)
    }

    eventEmitter.addListener('event', eventEmitted)

    // eventEmitted listeners are removed when each client disconnects.
    req.on('close', () => {
        eventEmitter.removeAllListeners()
    })
})
但是,如前所述,由于无法检测客户端连接的状态,Heroku会在客户端连接后立即触发
close
事件,从而导致执行
eventEmitter.removeAllListeners()
。当然,我的客户此后不会收到任何通知。我已将路线更改如下,以便在Heroku上运行:

// Server Sent Events route for receiving realtime notifications when events are emitted.
router.get('/updates', (req, res) => {
    // eventEmitted listeners are added for the most recently connected client.
    const eventEmitted = (data) => {
        res.write(`data: ${JSON.stringify(data)}\n\n`)
    }

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

    res.write('\n')

    eventEmitter.removeAllListeners()
    eventEmitter.addListener('event', eventEmitted)
})
结果是,由于删除了
req.on('close')
,Heroku上不会出现
H27
错误,因为它不会尝试检测客户端状态。缺点是只有最近连接的客户端才能从服务器接收实时更新。所有以前连接的客户端都不会附加事件侦听器来向其发送更新。这对我来说是有效的,因为我是应用程序的唯一用户,但如果您有一个以上的客户端或一个以上的应用程序实例正在运行,那么这将不起作用

另一个选项是删除('close')上的
req.on,永远不要删除任何添加的侦听器。这允许您的所有客户端接收更新,但代价是您的服务器将为每个断开连接的客户端提供大量孤立事件侦听器,最终导致内存泄漏


对于大多数人来说,这不是一个真正可以接受的解决方案,但却是我唯一能想到的解决方案。如果有人有更好的解决方案,请随时在此处发布。

您能解决吗?我有完全相同的问题。有趣的是,当我第一次启动服务器时,它就工作了,但随后重新加载一个新页面(在H27错误之前,它可能工作1秒),然后它又停止工作。我得到
code=H27 desc=“客户端请求中断”
。我几乎一整天都在为它头疼,因为我认为这是我的代码中的一个问题,但我认为是的。这是一个特定于Heroku的问题。您是否碰巧使用了Heroku插件?不幸的是,没有。问题仍然存在。好消息是,自上次以来,H27似乎没有出现任何问题。应用程序似乎运行良好,后端似乎不会错过消息。keep alive消息配置为50秒,这符合Heruko的55秒要求,所以我还没有弄清楚原因是什么…你说它不会导致问题是什么意思?在断开连接之前,您是否能够始终从服务器接收到客户端浏览器的实时通知?在我的例子中,由于我依赖事件处理程序(根据客户端的连接添加和删除)来发送消息,因此在H27请求中断发生后,“我的服务器”删除了将这些消息发送到客户端的事件处理程序,导致客户端不再接收这些消息。您能否告诉我,您是如何配置服务器使其在无法检测客户端断开连接的情况下工作的?感谢@Arik MirmanThank you@哲学家的回复。不幸的是,我的案例涉及多个同时连接的用户。