单页应用中sse连接必须主动绑定页面/路由生命周期并显式关闭——react用useeffect清理函数、vue2用beforedestroy、vue3用onbeforeunmount;需按路由上下文精准管理多实例,服务端应配合监听关闭事件并终止推送。

单页应用里管理 SSE 连接生命周期,关键不是“等它自己断”,而是主动控制——连接必须和当前页面/路由的存续状态严格绑定。不手动关,它就在后台一直收数据、占内存、发请求,哪怕用户早已离开那个页面。
路由切换前必须显式关闭 EventSource
EventSource 不会随组件卸载自动销毁,浏览器也不会替你清理。只要没调 .close(),它就持续活着。
- React:在 useEffect 清理函数 中执行
eventSource?.close() - Vue 2:在 beforeDestroy 钩子中关闭
- Vue 3:用 onBeforeUnmount 执行关闭逻辑
- 避免把 EventSource 声明在模块顶层或全局对象里,否则无法绑定到具体页面生命周期
按路由上下文精准管理多个实例
一个应用常有多个 SSE 流(如通知、订单、聊天),不能笼统“全关掉”,得知道关的是哪个。
- 创建时打标记:
es.__routeContext = '/dashboard' - 路由守卫中(如
router.beforeEach)遍历已存在实例,对 __routeContext 匹配旧路径 的执行.close() - 更健壮的做法是用 WeakMap 存储
route → eventSource映射,避免强引用阻碍垃圾回收
服务端配合感知连接关闭并终止推送
前端关了,服务端若还往这个连接发数据,就是无效带宽 + 资源浪费。需要双向协同:
- 客户端关闭前可发轻量终结请求(如
POST /api/sse/close?session=xxx),服务端据此清掉对应会话和推送任务 - 服务端监听底层响应流的
close事件(如 Node.js 的res.on('close')),及时释放内存和连接池资源 - 每个 SSE 请求带上
X-Route-Path或Referer,服务端按当前活跃路由动态过滤推送内容
防止重复连接与重连失控
快速来回切换路由容易触发多次新建连接,旧连接还没关,新连接又建起来。
- 封装工厂函数,用 Map 缓存按路径/业务类型区分的实例,确保每次只启一个、关一个
- 加最小重连间隔(如 1.5 秒),防止因状态混乱触发高频重建
- 在
visibilitychange事件中判断页面是否进入后台,后台时不主动重建,前台恢复时再检查连接状态并按需重连
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











