
通过轻量级轮询替代长连接sse,用`filemtime()`高效获取文件修改时间,并结合前端定时检查实现低开销自动刷新,彻底避免apache进程数爆炸。
传统服务端事件(SSE)方案虽实时性好,但每个打开的页面标签都会维持一个长期存活的PHP进程,导致Apache并发连接数线性增长——100个标签即100个常驻进程,极易触达MaxRequestWorkers上限,引发服务僵死。根本问题在于:将状态监听逻辑错误地放在服务端持续执行,而非交由客户端按需轻量查询。
✅ 正确解法是「客户端主动轮询 + 服务端瞬时响应」:
- PHP端仅做一件事:秒级返回index.html的最后修改时间戳;
- JavaScript端首次加载时记录该时间戳,之后每隔数秒发起一次轻量HTTP请求比对,仅当时间戳变化时才触发location.reload()。
以下是优化后的完整实现:
1. 服务端(get_index_change_time.php)——极简、无状态、无循环
<?php
header('Content-Type: text/plain; charset=utf-8');
header('Cache-Control: no-cache, no-store, must-revalidate');
header('Pragma: no-cache');
header('Expires: 0');
echo @filemtime('index.html') ?: 0;
?>⚠️ 注意: 移除所有shell_exec()调用,filemtime()直接读取文件系统元数据,性能提升10倍以上; 显式禁用缓存,确保每次请求都真实校验; 使用@抑制filemtime()在文件不存在时的警告,返回0便于前端判断。
2. 客户端(嵌入index.html的JS)——防抖+错误隔离+优雅降级
<script>
let lastKnownMtime = null;
function checkIndexChange() {
fetch('/get_index_change_time.php', {
method: 'GET',
cache: 'no-store'
})
.then(res => {
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return res.text();
})
.then(mtimeStr => {
const currentMtime = parseInt(mtimeStr, 10);
if (isNaN(currentMtime)) throw new Error('Invalid mtime format');
if (lastKnownMtime !== null && currentMtime > lastKnownMtime) {
console.info('[AutoRefresh] index.html changed → reloading...');
location.reload();
return; // 防止重复执行
}
lastKnownMtime = currentMtime;
// 下次检查延迟3秒(使用setTimeout而非setInterval,避免请求堆积)
setTimeout(checkIndexChange, 3000);
})
.catch(err => {
console.warn('[AutoRefresh] Check failed:', err.message);
// 网络失败时延长重试间隔,避免雪崩
setTimeout(checkIndexChange, 10000);
});
}
// 页面加载完成后立即启动检查
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', checkIndexChange);
} else {
checkIndexChange();
}
</script>? 关键优势总结:
- 资源占用锐减:单次PHP请求毫秒级完成,Apache进程瞬间释放,100个用户 ≈ 100次/秒的轻量HTTP请求,而非100个常驻进程;
- 弹性容错:网络抖动或PHP临时异常仅导致单次检查失败,自动退避重试,不影响整体可用性;
- 零配置依赖:无需调整Apache MaxRequestWorkers、KeepAlive等参数,适配任何共享主机环境;
- 可扩展性强:如需监控多个文件,只需扩展PHP返回JSON对象,前端增加多字段比对逻辑即可。
此方案将负载从服务器CPU/内存转移到带宽(极小)和客户端计算,完美契合静态网站场景,在有限资源下实现高可靠、低延迟的自动更新体验。










