PHP Server Sent Events用无限循环时出现500错误求助
问题描述
尝试用PHP实现SSE,按照教程使用无限while循环维持连接,但运行几分钟后就会出现500错误,无法持续发送数据。我的应用必须保持无限循环运行,因为需要通过TCP套接字接收硬件设备的更新,必须维持套接字连接不中断。
仅在使用while循环时会触发错误;移除循环后客户端会每3秒自动重连,不符合业务需求。
环境配置
- PHP版本:7.3.33
- 服务器环境:Windows Server 2022/2016 + IIS 10
- PHP配置:
php.ini中output_buffering和zlib.output_compression均设为Off - FastCGI配置:PHP的FastCGI Handler中
responseBufferLimit设为0
测试代码
sse.php
<?PHP header('Content-Type: text/event-stream'); header('Cache-Control: no-cache'); while(true) { $now = date('r'); echo "data: The time is : {$now}\n\n"; @ob_flush(); flush(); sleep(2); } ?>
test.html
<!doctype html> <html> <head> <meta charset="UTF-8"> <title>Untitled Document</title> </head> <body> <script> var source = new EventSource("sse.php"); source.onopen = function(e) { console.log("The connection to your server has been opened"); } source.onmessage = function(e) { console.log ("message: " + e.data); } source.onerror = function(e) { console.log("The server connection has been closed due to some errors"); } </script> </body> </html>
PHP错误日志
日志中的错误看起来与当前问题无关:
[17-Nov-2022 21:26:28 UTC] PHP Warning: Module 'mysqli' already loaded in Unknown on line 0
[17-Nov-2022 21:26:28 UTC] PHP Warning: Module 'mbstring' already loaded in Unknown on line 0
[17-Nov-2022 21:26:28 UTC] PHP Deprecated: Directive 'track_errors' is deprecated in Unknown on line 0
已尝试的无效方案
已按照教程修改以下配置,但问题仍未解决:
- 将
php.ini中output_buffering和zlib.output_compression设为Off - 将PHP的FastCGI Handler设置中
responseBufferLimit设为0
解决方案
针对Windows IIS环境下PHP SSE无限循环触发500错误的问题,需从以下关键配置入手调整:
1. 取消PHP脚本执行时间限制
默认PHP脚本执行时间限制为30秒,无限循环会触发超时导致500错误。可通过两种方式修改:
- 编辑
php.ini:max_execution_time = 0 - 在
sse.php开头添加代码:ini_set('max_execution_time', 0);
注意:CLI模式下max_execution_time默认是0,但FastCGI模式需显式设置。
2. 调整IIS FastCGI超时设置
IIS的FastCGI进程有自身超时机制,即使PHP超时设为0,进程仍可能被回收:
- 打开IIS管理器,找到FastCGI设置
- 找到对应PHP处理程序,双击进入编辑界面
- 将活动超时和请求超时修改为较大值(如86400秒,即24小时),或根据业务需求调整
3. 禁用IIS输出缓存
即使PHP关闭了输出缓冲,IIS自身可能仍会缓冲text/event-stream类型的输出:
- 在IIS管理器中找到目标网站,打开输出缓存
- 点击添加,选择
text/event-streamMIME类型,取消勾选“启用缓存” - 检查网站HTTP响应标头,确保无强制缓存的配置
4. 优化脚本连接检测
在循环中添加客户端断开检测,避免无效占用资源,同时移除错误抑制以便排查缓冲问题:
<?PHP header('Content-Type: text/event-stream'); header('Cache-Control: no-cache'); header('Connection: keep-alive'); // 禁用脚本超时 ini_set('max_execution_time', 0); while(true) { // 检测客户端是否断开连接 if (connection_aborted()) { exit(); } $now = date('r'); echo "data: The time is : {$now}\n\n"; ob_flush(); flush(); sleep(2); } ?>
5. 调整IIS应用程序池回收设置
IIS应用程序池默认定期回收进程,会直接中断SSE连接:
- 打开应用程序池的高级设置
- 调整回收参数:禁用“固定时间间隔”回收,或根据业务需求延长回收周期
- 将闲置超时设为0,避免闲置时回收进程
内容的提问来源于stack exchange,提问作者forde52

