PHP实现SSE推送成功的关键是禁用所有缓冲层并防止超时中断,需关闭output_buffering、zlib压缩、Nginx proxy_buffering,调用ob_flush()和flush(),设置set_time_limit(0),严格遵循data:\n\n格式,并添加心跳与进程管理。

PHP实现SSE推送,核心不是“写对格式”,而是“让数据不卡在中间”。多数失败不是代码错,是输出被缓冲、被代理拦、被超时杀掉。
PHP必须禁用所有缓冲层,否则echo "data:xxx\n\n"根本发不出去
浏览器看到的“连接建立但没数据”,90%是PHP或Web服务器把输出吞了。不能只靠flush()——它只刷PHP自己的输出缓冲,前面还有zlib压缩、output_buffering、Nginx代理缓冲三道墙。
-
ini_set('output_buffering', 'off')或在php.ini里关掉;ob_end_clean()清掉已激活的缓冲区 -
ini_set('zlib.output_compression', false)关zlib,否则压缩会等满块才发 -
header('X-Accel-Buffering: no')告诉Nginx别缓存(Apache用Header set X-Accel-Buffering "no") - 必须调用
ob_flush()和flush()两层刷新,顺序不能反
set_time_limit(0) 不是可选项,是保命操作
PHP默认执行超时30秒,而SSE连接本该持续数分钟甚至更久。一旦超时,脚本终止,连接断开,EventSource自动重连——但重连间隔会指数退避,用户感知就是“消息突然停5秒,再跳一条”。
- 放在
header()之后、循环之前,避免被其他逻辑覆盖 - 如果用FastAdmin/ThinkPHP等框架,注意它们可能在控制器基类里设了全局超时,需手动重置
- 生产环境建议加心跳检测:每30秒发一次空
data:\n\n,防代理主动断连
事件格式看似简单,但data:换行和空行缺一不可
SSE协议对换行符极其敏感:data:后必须跟\n,每个事件结尾必须是\n\n(两个LF)。Windows换行\r\n会导致部分浏览器解析失败。
立即学习“PHP免费学习笔记(深入)”;
- 用
PHP_EOL不安全,直接硬写"\n";多行data:内容每行末尾都要\n,最后再补一个\n - 不要省略空行:
echo "data:hello\n\n"✅,echo "data:hello\n"❌(浏览器收不到) - 自定义事件用
event:xxx\n,但data:仍需存在,否则事件会被忽略
Nginx配置漏掉proxy_buffering off,前端永远收不到首条消息
即使PHP端全配对,Nginx默认开启proxy_buffering on,它会攒够64KB或等响应结束才转发——而SSE响应永不结束,结果就是首条消息卡住不动。
- 在location块里加:
proxy_buffering off;和proxy_cache off; - 同时设置超时:
proxy_read_timeout 86400;(1天),避免Nginx主动断连 - 若用Cloudflare,需关闭“Always Online”和“Auto Minify”,它们会破坏流式响应
最易被忽略的点:SSE连接是HTTP长连接,但PHP脚本每次请求只能服务一个客户端。高并发时得配合Redis Pub/Sub或进程管理(如Supervisor守护),否则一个用户连上就占住一个PHP-FPM进程,很快打满。别只盯着格式对不对,先看连接能不能活过10秒。



















