PHP中While循环无法捕获Session变更的SSE问题排查
问题原因分析
核心原因:PHP Session的内存缓存机制
在SSE长连接的循环进程中,PHP会对Session数据做内存缓存:
- 第一次调用
session_start()时,PHP会从磁盘读取Session文件内容并加载到内存的$_SESSION数组中。 - 后续即使调用
session_write_close()释放了Session文件锁,再次调用session_start()时,PHP会直接复用内存中已有的缓存数据,不会重新从磁盘读取其他脚本修改后的最新Session内容。 - 而第二段无循环的代码是单次请求,每次刷新页面都会启动新的PHP进程,
session_start()会重新读取磁盘上的最新Session文件,因此能捕获到变更。
解决方法
修改循环内的Session操作逻辑,强制PHP每次都重新读取磁盘上的最新Session文件,具体有两种可行方案:
方案1:清空Session内存缓存 + 强制无缓存读取
在每次循环中,读取Session后清空$_SESSION数组,并在下次session_start()时强制关闭缓存:
<?php header('Content-Type: text/event-stream'); header('Cache-Control: no-cache'); header('Connection: keep-alive'); function sendEvent($event, $data) { echo "event: $event\n"; echo "data: $data\n\n"; ob_flush(); flush(); } // Check signing status and send events while (true) { // 强制关闭Session缓存,确保每次重新读取文件 session_start(['cache_limiter' => 'nocache']); $status = $_SESSION['signing_status']; session_write_close(); // 立即释放文件锁 $_SESSION = []; // 清空内存中的Session缓存 sendEvent("event",$status); sleep(4); } ?>
方案2:使用read_and_close参数(PHP 7.0+)
PHP 7.0及以上版本支持read_and_close参数,调用session_start()时直接读取Session并关闭文件,同时避免内存缓存复用:
<?php header('Content-Type: text/event-stream'); header('Cache-Control: no-cache'); header('Connection: keep-alive'); function sendEvent($event, $data) { echo "event: $event\n"; echo "data: $data\n\n"; ob_flush(); flush(); } // Check signing status and send events while (true) { // 读取Session后立即关闭,自动释放锁且不缓存 session_start(['read_and_close' => true]); $status = $_SESSION['signing_status']; $_SESSION = []; // 清空内存缓存 sendEvent("event",$status); sleep(4); } ?>
额外注意事项
- 确保其他修改Session的脚本在操作完成后调用
session_write_close(),避免Session文件锁导致SSE循环无法读取。 - 若使用非文件型Session存储(如Redis、Memcached),内存缓存问题会自动消失,因为这类存储是直接读取远程数据而非本地内存缓存。
内容的提问来源于stack exchange,提问作者Kevin Lindmark
相关产品推荐
相关产品推荐

