PHP输出缓冲必须关闭,否则SSE无法实时推送;需设置正确响应头、严格遵循消息格式、处理连接断开与重连,并防止Web服务器及PHP-FPM中间层缓存。

PHP 输出缓冲必须关掉,否则 SSE 不会实时
SSE(Server-Sent Events)依赖服务端持续写入响应流,而 PHP 默认开启输出缓冲(output_buffering),会导致数据攒在缓冲区里不发出去。不关它,前端永远收不到第一条消息。
实操建议:
- 脚本开头加
ob_end_flush()和ob_flush(),再调用flush();更稳妥的做法是直接禁用:ini_set('output_buffering', 'Off')、ini_set('zlib.output_compression', 'Off') - Apache 下还要确认
mod_deflate没对 SSE 响应做压缩(它会拦截并缓存响应),Nginx 则需关掉gzip或用gzip off;针对 SSE 路由 - 如果用了 PHP-FPM,
buffer_size设为 0(或0s)避免 FPM 层缓存
header 设置不能错,Content-Type 和 Cache-Control 是关键
SSE 要求响应头严格符合规范,漏掉或写错一个,浏览器就当普通 HTTP 响应处理,不会建立 EventSource 连接。
必须设置的 header:
立即学习“PHP免费学习笔记(深入)”;
HISUI 前端框架基础开发指南。HISUI 是基于 easyui 二次开发的 jQuery UI 组件库,专为医疗信息系统设计。当涉及 HISUI 组件开发、jQuery easyui 表格/表单/布局/窗口、医疗系统前端页面编写时使用此 skill。 涵盖 40 个组件的官方文档参考,支持声明式与编程式两种初始化方式,提供 $cm/$m 数据访问方法。
-
header('Content-Type: text/event-stream')—— 类型错成application/json或漏掉,连接直接失败 -
header('Cache-Control: no-cache')—— 浏览器可能缓存初始响应,后续推送全失效 -
header('Connection: keep-alive')—— 显式声明长连接,避免代理/CDN 中断 - 可选但推荐:
header('X-Accel-Buffering: no')(Nginx)防止其内部缓冲
每条消息必须以 data: 开头,结尾用双换行
SSE 协议规定消息格式极其简单,但容错极低:字段名必须小写,冒号后要空格,每条消息末尾必须是两个 \n(即 \n\n)。少一个换行,浏览器就卡住不解析。
正确示例:
data: {"status":"ok","time":1716234567}
data: hello
常见错误:
- 用
echo "event: ping\ndata: alive\n\n"却忘了echo默认不带换行,得手动补\n - JSON 字符串里混入 HTML 实体或未转义双引号,导致前端
JSON.parse()报错 - 循环中没控制频率,高频
echo+flush()可能触发 Apache 的TimeOut或 Nginx 的proxy_read_timeout
客户端 EventSource 连接断开后,重连逻辑得自己管
PHP 无法主动感知客户端断开(除非用心跳+超时检测),而浏览器 EventSource 在网络抖动或服务重启后会自动重连——但它只按固定规则重试(首次延迟 ~5s,之后指数退避),且不会传 cookie 或自定义 header。
实际要注意的点:
- 后端别假设连接永久存在,每次
echo前先检查connection_status() === CONNECTION_NORMAL,否则可能向已断连接写数据,触发警告甚至进程终止 - 需要鉴权?别依赖 session cookie(重连时不发),改用 URL 参数传 token,或前端初始化时先 fetch 一次获取临时凭证
- 若需保证消息不丢,服务端得维护游标(如 last_id),客户端重连时带上上次收到的 ID,服务端从该位置继续推


















