当前位置: 首页 > 知识库问答 >
问题:

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

耿炎彬
2023-03-14

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

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

以下是我在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请求id=c4c4e2fd-16ca-4292-a27b-2a70b12b16fa fwd=“77.138.167.76”dyno=web。1连接=1ms服务=9499ms状态=499字节=协议=https

这是由以下GET请求导致的:2020-10-17T08:48:55.027638 00:00 app[web.1]:客户端8已注册

你知道我该怎么克服吗?我的问题是,我的应用程序在很大程度上依赖于SSE,如果我现在必须切换到另一种机制(例如socket),这将需要相当大的努力。

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

我仍然没有找到解决这个问题的方法,所以请大家随时发表评论。

共有1个答案

方风华
2023-03-14

我已经找到了一个非常黑客的解决方案来解决这个问题,因为我是这个应用程序的唯一用户。

首先,一些上下文。问题是由于某种原因,部署在Heroku上的应用程序虽然允许客户端成功连接到SSE路由,但无法检测到客户端连接的状态。客户端连接后,在服务器无法检测到客户端的短时间内,服务器上会发布一个code=H27 desc="Client Request Interunc"错误,它将此视为客户端连接已关闭的标志。由于它认为客户端连接已关闭,它自然会触发一个关闭事件,导致在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无法检测客户端连接的状态,因此在客户端连接后不久会触发关闭事件,从而导致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)
})

结果是,因为<代码>请求。删除('close'),Heroku上不会发生错误,因为它不会尝试检测客户端状态。缺点是,只有最近连接的客户端才能从服务器接收实时更新。所有以前连接的客户端都不会附加事件侦听器来向其传递更新。这对我来说很有用,因为我是该应用程序的唯一用户,但如果您有多个客户端或多个应用程序实例正在运行,则这将不起作用。

另一种选择是完全删除req.on('关闭'),并且从不删除任何添加的侦听器。这允许您的所有客户端接收更新,但您的服务器将为每个断开连接的客户端提供大量孤立事件侦听器,最终导致内存泄漏。

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

 类似资料:
  • 为什么每个站点都解释说在SSE中,客户端和服务器之间的单个连接保持打开状态“使用SSE,客户端发送标准HTTP请求请求事件流,服务器最初以标准HTTP响应响应并保持连接打开” 然后,当服务器决定可以向客户端发送数据,而我试图实现SSE时,每隔几秒钟就会看到fiddler请求被发送 对我来说,这感觉就像是长时间的投票,没有一个连接保持打开。 此外,并不是服务器决定向客户机发送数据,而是只有在客户机发

  • 为什么每个站点都解释说,在SSE中,客户端和服务器之间只有一个连接保持打开状态“在SSE中,客户端发送一个标准的HTTP请求,请求一个事件流,服务器最初以标准的HTTP响应进行响应,并保持连接打开” 然后,当服务器决定它可以向客户机发送数据时,我正在尝试实现SSE,我会看到每隔几秒钟发送一次fiddler请求 对我来说,这感觉像是长时间的轮询,没有一个连接保持打开。

  • 我有一个ASP。net core 3.1服务器项目,它有一个非常简单的API发送单向服务器发送事件(SSE),如下所示: 现在,我想通过C#UWP客户端接收这些事件。很遗憾,我只收到第一个事件: 如何在UWP中创建行为以始终监听该连接并接收我可以进一步处理的事件?

  • 我有一个NodeJS应用程序,它使用服务器发送事件(SSE)路由将更新从服务器发送到客户端。在我的本地开发环境中,这非常有效,因为客户端始终保持与SSE路由的连接,并且在断开连接时尝试立即重新连接。 然而,一旦我将我的应用程序部署到Heroku,一切都出了问题。在没有通过SSE路由发送任何数据的几秒钟内,我在客户端收到一个503服务不可用的错误,客户端失去了与服务器的连接,因此无法接收任何实时更新

  • 我正在开发一个连接到服务器的web应用程序,我需要服务器在给定的时间向客户机推送一些信息。 有人会强调这些技术吗(也许还有其他一些推动技术。)这符合我的问题,哪一种情况更适合每一种情况? 非常感谢,我想我在这个领域完全迷失了。