.htaccess重写规则导致PHP中Server-Sent Events(SSE)失效
解决PHP SSE与.htaccess重写规则兼容的问题
方案一:让SSE脚本绕过重写路由
如果不需要通过应用入口处理SSE请求,最简单的办法是修改.htaccess,让你的SSE脚本直接被访问,不经过index.php:
# 优先匹配SSE脚本,直接放行 RewriteRule ^sse\.php$ - [L] # 原有重写规则 RewriteCond %{REQUEST_URI} !favicon.ico(.*) RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^(.+)?$ index.php [QSA,L]
把sse.php换成你实际的SSE脚本文件名,[L]标记会让匹配到的请求跳过后续重写规则,直接访问脚本本身,避开应用内部的缓冲、会话锁等干扰。
方案二:在应用入口处理SSE请求(需保留路由)
如果必须让SSE请求经过index.php(比如需要权限验证),要在入口文件最开头拦截SSE请求,提前处理缓冲和会话问题:
// index.php 最顶部添加 if (strpos($_SERVER['REQUEST_URI'], '/sse') !== false) { // 强制关闭所有输出缓冲 ini_set('output_buffering', 'off'); while (ob_get_level() > 0) { ob_end_clean(); } // 释放会话锁(如果应用启用了session) if (session_status() === PHP_SESSION_ACTIVE) { session_write_close(); } // 引入你的SSE逻辑 require_once __DIR__ . '/path/to/your-sse-script.php'; exit; // 必须终止后续代码执行,避免应用逻辑干扰 } // 原有应用初始化代码...
为什么路由到index.php会失效?
核心原因是应用入口的全局逻辑会破坏SSE的运行条件:
- 输出缓冲:多数PHP应用/框架会在入口开启全局输出缓冲(
ob_start()),即使SSE脚本里关闭缓冲,入口的缓冲已经存在,导致数据无法即时flush到客户端。 - 会话锁:如果应用在入口启动了
session_start(),会话文件会被独占锁定,直到脚本结束或手动释放锁,这会阻塞SSE的循环输出。 - 中间件干扰:路由、日志、响应处理等中间件可能会修改响应头、添加额外输出,破坏SSE要求的
text/event-stream格式和长连接状态。
额外注意事项
- 检查服务器配置:Apache的
Timeout不要设得太短(至少大于SSE的运行时长),Nginx需设置proxy_read_timeout 300s;(或更长)支持长连接。 - 确保SSE的响应头不被覆盖:应用的响应类或中间件可能会重写
Content-Type,要保证text/event-stream最终生效。 - 用浏览器开发者工具排查:在Network面板查看SSE请求的响应头,确认
Cache-Control、Connection等头是否符合要求,同时观察数据流是否持续输出。
内容的提问来源于stack exchange,提问作者Pablo
相关产品推荐
相关产品推荐

