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

PHP实现Server-Sent Events时readyState始终为0及批量事件问题排查

关于Server-Sent Events(SSE)的两个问题

问题1:客户端连接时readyState始终为0

我正在使用EventSource(SSE API)实现Server-Sent Events,按照示例搭建Demo,但客户端连接时readyState始终处于0状态;移除PHP文件中的while循环后,连接能正常工作一次但随后中断。

相关代码

PHP代码:

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

while(true) {
    $time = date('r');
    echo "data: The server time is: {$time}

";
    ob_end_flush();
    flush();
    session_write_close();
    if(connection_aborted()) { break; }

    sleep(1);
}

JavaScript代码:

var evtSource = new EventSource('/pingen/PingenEventHandler.php');
console.log(evtSource.withCredentials);
console.log(evtSource.readyState);
console.log(evtSource.url);

evtSource.onopen = function() {
    console.log("Connection to server opened.");
};

evtSource.onmessage = function(e) {
    console.log(e.data)
};

evtSource.onerror = function(event) {
    console.log(event);
    console.log("EventSource failed.");
};

问题2:事件批量到达而非逐个发送

更新PHP代码后,客户端可以接收事件,但事件并非逐个发送,而是约20个一起到达。

更新后的PHP代码:

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

while(true) {
    $data = [
        'name' => 'Rasmus Lerdorf'
    ];

    $curDate = date(DATE_ISO8601);

    echo "event: sse
";
    echo "data: This is a message at time " . $curDate . "

";
    echo str_pad('', 4096) . "
";
    ob_end_flush();
    flush();
    session_write_close();
    if(connection_aborted()) { break; }

    sleep(1);
}

问题1的可能原因及解决方案

  • 输出缓冲未完全关闭:PHP的输出缓冲或服务器端(Apache、Nginx)的额外缓冲会阻塞内容实时发送。可在脚本开头添加ob_start()手动控制缓冲;检查服务器配置,比如关闭Apache的mod_deflate、Nginx的gzip对SSE接口的压缩。
  • 会话锁定问题:若脚本执行前已开启会话,session_write_close()的调用时机可能太晚。建议在输出任何内容前就调用该函数,或直接在SSE接口中禁用会话(无需会话时)。
  • 服务器长连接限制:Apache的Timeout、Nginx的proxy_read_timeout等配置可能提前断开长连接,导致客户端停留在连接中状态。需调整超时时间至大于SSE发送间隔。
  • 跨域限制:若前端与SSE接口不同域名,需在PHP中添加跨域头,比如header("Access-Control-Allow-Origin: 你的前端域名");,否则浏览器会阻止连接建立。

问题2的可能原因及解决方案

事件批量到达核心是输出缓冲未即时刷新,常见原因及解决:

  • 服务器端缓冲阈值过高:你添加的4096字节填充可能未达到服务器缓冲阈值(比如Nginx默认8KB),可增大填充至str_pad('', 8192);或在服务器配置中禁用该接口缓冲:Nginx添加fastcgi_buffering off;,Apache设置SetEnv no-gzip 1。
  • PHP自身缓冲未关闭:检查php.ini中output_buffering是否为Off,或在脚本开头用ini_set('output_buffering', 0);强制关闭。
  • 网络代理/CDN缓冲:若存在代理或CDN,需配置其不对SSE接口的响应进行缓冲,或直接绕过缓存访问该接口。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 07:15:36