You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Server-Sent Events连接为何循环触发open事件?如何解决?

问题解答:SSE客户端持续重连的原因与服务器过载风险解决

你的担忧是正确的

当服务端主动结束SSE连接(比如有限循环执行完毕),EventSource的默认行为会自动重试连接(默认间隔3秒)。大量客户端不断发起新的连接请求,会快速消耗服务器的连接数、进程/线程资源,尤其在高并发场景下,极易导致服务器过载,出现响应变慢、连接失败甚至服务崩溃的情况。

问题根源

你修改后的服务端代码会在循环结束后正常关闭HTTP连接,而EventSource规范设计时就包含了「连接意外关闭时自动重连」的机制,用于应对网络波动、服务端临时故障等场景。但你的场景中是服务端主动结束连接,不属于意外情况,却触发了默认的重连逻辑,导致客户端不断建立新连接。

解决方法

1. 服务端发送明确的结束标记(推荐)

根据SSE规范,当服务端发送data: [DONE](或自定义的结束标识)并结束响应后,客户端收到该标记会自动停止重连。

修改后的服务端代码:

<?php
header("Cache-Control: no-store");
header("Content-Type: text/event-stream");

$counter = rand(1, 10);
for ($x = 0; $x < 5; $x++) {
  // 发送ping事件
  echo "event: ping\n";
  $curDate = date(DATE_ISO8601);
  echo 'data: {"time": "' . $curDate . '"}';
  echo "\n\n";

  $counter--;
  if (!$counter) {
    echo 'data: This is a message at time ' . $curDate . "\n\n";
    $counter = rand(1, 10);
  }

  ob_end_flush();
  flush();

  // 检测客户端是否断开连接
  if (connection_aborted()) break;

  sleep(1);
}

// 发送结束标记,通知客户端停止重连
echo "data: [DONE]\n\n";
ob_end_flush();
flush();
?>

2. 客户端主动关闭连接

在客户端监听消息事件,收到服务端的结束标记后,手动调用evtSource.close()终止连接,避免自动重连。

修改后的客户端代码:

var evtSource = new EventSource('http://localhost/ssevent.php');

// 监听ping事件
evtSource.addEventListener('ping', function(e) {
    console.log(e.data);
}, false);

// 监听普通消息,处理结束标记
evtSource.addEventListener('message', function(e) {
    if (e.data === '[DONE]') {
        evtSource.close();
        console.log("Connection closed intentionally.");
        return;
    }
    console.log(e.data);
}, false);

evtSource.addEventListener('open', function(e) {
    console.log("Connection was opened.");
}, false);

evtSource.addEventListener('error', function(e) {
    if (e.readyState === EventSource.CLOSED) {
        console.log("Error, connection was closed.");
    }
}, false);

3. 优化长连接场景(如果需要持续推送)

如果你的业务需要持续的SSE推送,不要用有限循环,而是保留while(true),但要优化资源占用:

  • 定期检测客户端连接状态(通过connection_aborted()),及时关闭僵尸连接
  • 使用异步PHP框架(如Swoole、ReactPHP)代替传统PHP-FPM,这类框架可以用单进程/线程处理数千个长连接,避免PHP-FPM进程耗尽的问题

内容的提问来源于stack exchange,提问作者warriorforce

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 17:17:43