Chrome 开发工具中未报告僵尸 SSE 连接

问题描述 投票:0回答:1

背景

我正在构建一个 Web 应用程序,供内部使用 HTTP/1.1。 它没有 TLS,因此不支持 HTTP/2,也不支持 HTTP/3 或 QUIC(这些新协议可以解决问题,但目前无法访问)。

客户使用:

  • 一些静态资源
  • 一些API端点(都非常快,都使用Fetch API)
  • 2 个并发且长时间运行的服务器发送事件流

所有请求均由 nginx 提供服务,但看起来我的问题与它无关。

问题

有时,刷新页面后,某些请求会停滞很多秒。 Chrome 会停止请求,即导航或 JS Fetch API 发起请求后,Chrome 决定不再发送 HTTP 请求。 DevTools 没有给出任何提示来理解为什么会发生这种情况。

Chrome Dev Tools screenshot

我尝试排除一些常见问题:

  • 较高优先级请求:这是一个Fetch,因此不应将其视为低优先级请求;此外,没有其他请求被优先考虑。
  • 服务器工作者读到:我没有看到任何错误消息,但很明显该请求没有脱离 Chrome。
  • QUIC:我在 HTTP/1.1 上运行,不是 HTTP/2,不是 HTTP/3,不是 QUIC。
  • 用于缓存的磁盘空间分配:我尝试在 Fetch 中指定
    {cache: 'no-store'}
    ,但没有成功。
  • Chrome 每个源规则最多有 6 个 TCP 连接:这实际上是我的第一次检查。开发工具中显示的 SSE 连接数永远不会超过 2 个;另一个请求完成后,停滞的请求似乎不会启动。我没有看到任何其他可能持有 TCP 套接字的待处理请求。没有其他选项卡打开。剧透:这个限制实际上已经生效了。

经过一些检查,我花了一些时间将 nginx 配置为始终在所有响应中发送

Connection: close
作为 HTTP 标头,以便客户端不会尝试为即将到来的请求重用相同的 TCP 连接。 我认为 Chrome 乐观地停止重用 SSE 请求的 TCP 连接,假设它会在短时间内释放。 这可以有效地防止连接重用,但这并不是问题的原因——Chrome 中没有如此乐观的停滞,这是有充分理由的。

进入 Wireshark

并发 SSE 连接实际上已达到六个连接限制。

重点是:这些 SSE 连接没有被任何选项卡使用,没有显示在开发工具中,并且底层 TCP 保持打开状态。事实上,Wireshark 允许我看到 TCP 4 路终止握手:

  • 开始很晚,很久之后SSE就被刷新页面放弃了
  • 它发生在停滞的请求离开之前的片刻。
  • 由Chrome发起

更准确地说,捕获的 TCP 数据包的顺序是(见下面的屏幕截图):

  • (流 1)chrome > 服务器:FIN、ACK (僵尸 SSE 连接)
  • (流 1)服务器 > chrome:ACK
  • (流 13)chrome > 服务器:SYN
  • (流 13)服务器 > chrome:SYN、ACK
  • (流 13)chrome > 服务器:ACK
  • (stream 13) chrome > server: GET ... (停滞了很长时间的请求)

上述事件发生在 1.2 毫秒内,因此我很清楚 Chrome 决定推迟流 13 的请求,直到流 1 连接的客户端>服务器端关闭后。经过进一步检查,我还可以确认关闭流 1 实际上释放了当前打开的第六个连接(打开的 TCP 连接数从 6 减少到 5,允许为停滞的请求打开新连接) 。 (我省略了以下 ACK 以及上述数据包之后流 13 的完全终止)。

Wireshark screenshot

问题

为什么SSE连接仍然打开?

如何避免僵尸 SSE 连接?

为什么开发工具中没有报告僵尸连接?

google-chrome sockets google-chrome-devtools http-1.1 stalled
1个回答
0
投票

如何避免僵尸 SSE 连接?

解决方案:在卸载之前显式关闭服务器发送的事件源:

const sse = new EventSource(...)
const handler = () => {
    sse.close()
}
window.addEventListener('beforeunload', handler)
window.addEventListener('unload', handler)
© www.soinside.com 2019 - 2024. All rights reserved.