多开几个标签页挂 EventSource,新连接失败是撞上限了吗?

进度页、通知条、后台任务面板各自 new EventSource(...),一个标签还好使。同站点再开几个标签,新的连接开始挂起,或在失败和自动重连之间抖。前端半截 JSON 怎么拼,站里另一篇写过。这篇只盯浏览器对 Server-Sent Events 的连接模型,对照 MDN 的 Using server-sent events。

EventSource 本身在干什么

MDN 说:SSE 是一条单向连接,浏览器用 EventSource 收服务器推过来的事件,不能像 WebSocket 那样从客户端往同通道发事件。构造时传入生成事件的 URL。跨源时还可以带 withCredentials 选项。

默认行为里,客户端和服务器之间的连接若断开,浏览器会自动重连。要真正停掉,调用 .close()。只关标签却在别处仍握着实例、或错误回调里又 new 了一个,连接数会在你看不见的地方叠上去。调试时打开多个预发标签,每人一条 SSE,名额会很快被吃满。

服务端响应的 MIME 类型应是 text/event-stream。事件流按字段组织,常见有:

  • event:具名事件类型。没有的话走 message
  • data:载荷。多行 data: 会拼成一段
  • id:更新 Last-Event-ID
  • retry:重连等待毫秒数

以冒号开头的行是注释,可用来保活。这些是协议层约定,跟「能同时开几条连接」是两层问题。后端格式对了,前端仍可能因为连接名额满了而表现为「连不上」或疯狂重试。

连接数上限 MDN 怎么写

文档有一段醒目说明:在非 HTTP/2 场景下,SSE 会撞上最大打开连接数限制。多标签时尤其疼,因为限制是按浏览器计的,而且数字很低——文中写的是 6。Chrome 与 Firefox 上该问题被标成 Won’t fix。限制粒度是浏览器 + 域名:对 www.example1.com 可以开到那一档上限,对另一个域名再各算一档。

走 HTTP/2 时,同时存在的 HTTP 流数量由服务器与客户端通过 SETTINGS 协商,文档写默认常为 100。也就是说,同域多标签在 HTTP/1.1 上很容易摸到个位数上限。升级到 HTTP/2 后,上限通常宽得多,但仍不是「无限开标签」。MDN 这段明确点名的是 HTTP/2 协商。具体站点是不是已经上了 h2,以浏览器 Network 面板为准。

所以「新标签连不上」优先核对:页面是不是还在 HTTP/1.1。有多少标签/iframe 各自持有未 close 的 EventSource。失败后有没有在 onerror 里无节制地重建连接,把名额占满。一个页面里仪表盘、铃铛、任务列表各开一条到同一主机的 SSE,单标签就可能先占掉好几条。

排查时可以做的(不做歪招)

  • 标签隐藏或卸载时调用 eventSource.close(),避免后台页长期占着连接。
  • 同页只保留一条到同端点的 SSE,多组件共用,而不是每个小组件各 new 一条。
  • 看 Network 面板里连接是挂在 HTTP/1.1 还是 h2,以及服务器实际返回的 Content-Type 是不是 text/event-stream。
  • 需要浏览器→服务器双向、或连接模型不同时,评估 WebSocket 等方案。那是换通道,不是「破解」EventSource 上限。

后端用 FastAPI StreamingResponse 推流、客户端取消怎样才断得干净,是另一条线(发布后可补互链)。前端这边先把连接生命周期和协议版本看清,再和后端对取消语义。不写绕过浏览器连接限制的技巧,也不建议用隐藏窗口、多域名裸分片之类办法硬扩。那些做法脆、难维护,还可能踩安全与隐私策略。上限是浏览器实现与规范现实,产品侧用共享连接、及时 close、以及部署侧的 HTTP/2 更靠谱。

你们线上 SSE 是 HTTP/1.1 还是已经上 h2?多标签出问题之前,单个标签里有没有重复创建 EventSource?