Server-Sent Events 连接总是自动断开怎么办?

Zz皓阳 阅读 47

我在用 Server-Sent Events 做一个实时通知功能,后端是 PHP 写的。前端刚连上能收到几条消息,但过几秒就自动断开了,浏览器 Network 面板里看到状态变成 canceled。我查了下资料说 SSE 应该保持长连接,但不知道哪里出问题了。

后端我加了 header('Content-Type: text/event-stream');header('Cache-Control: no-cache');,还用了 flush(),但还是断。是不是我漏了什么设置?

header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');

while (true) {
    echo "data: " . json_encode(['time' => date('Y-m-d H:i:s')]) . "nn";
    flush();
    ob_flush();
    sleep(2);
}
我来解答 赞 6 收藏
二维码
手机扫码查看
2 条解答
技术一然
问题在于你的后端没有处理客户端断开连接的情况。加个 connection_aborted 检查,如果连接断开就跳出循环。
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');

while (true) {
if (connection_aborted()) break;
echo "data: " . json_encode(['time' => date('Y-m-d H:i:s')]) . "nn";
flush();
ob_flush();
sleep(2);
}
点赞
2026-03-24 09:05
a'ゞ新杰
兄弟,这个我之前也卡过好久,说几个最容易踩的坑:

1. PHP Session 锁住你了

如果你的网站在连 SSE 之前开过 session,比如用户登录什么之类的,session 会一直锁着,SSE 的长连接请求会被卡住直到超时。解决办法就是在 SSE 脚本里最开头写:

session_write_close();

2. Web 服务器的超时设置

Nginx 默认 60 秒就给你断了,不管你有没有数据。Apache 也一样。你需要在后端设置更长的超时时间:

set_time_limit(0);
ignore_user_abort(true);

还有 Nginx 那边的配置需要改:

proxy_read_timeout 300s;
proxy_send_timeout 300s;

或者直接用 Swoole 什么的长连接方案,但那是后话了。

3. 你的 flush 写法有点问题

ob_flush() 和 flush() 顺序反了,而且最好用 ob_implicit_flush(1) 代替手动 flush:

session_write_close();
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
header('Connection: keep-alive');
header('X-Accel-Buffering: no'); // 禁用 Nginx 缓冲

ob_implicit_flush(1);
ob_end_clean();

while (true) {
echo "data: " . json_encode(['time' => date('Y-m-d H:i:s')]) . "nn";
if (connection_aborted()) {
break;
}
sleep(2);
}

4. 还有一个坑

如果你的 PHP 输出被 Gzip 压缩了,flush 是没用的。确保没开 Gzip,或者在 .htaccess/nginx 配置里对 /sse 这个路由关掉压缩。

你先试试把 session_write_close() 加上,十有八九是这个问题。
点赞
2026-03-19 07:00