PHP实时输出时跨域被拦截的根本原因是CORS头必须在首响应块前发送,而实时输出易触发HTTP头自动发送;解决需确保header()调用在任何输出前、关闭所有缓冲层、禁用服务器压缩,并让首chunk包含完整CORS头。

PHP实时输出时跨域请求被拦截怎么办
能行,但默认不行——header('Access-Control-Allow-Origin: *') 必须在输出任何内容前设置,而实时输出(如 echo + flush())极易破坏这个前提。
为什么 header() 会失败或被忽略
PHP 的 header() 只能在 HTTP 响应头尚未发送时调用。一旦有任意输出(哪怕一个空格、BOM 或 echo ''),PHP 就自动进入 body 输出阶段,后续 header() 调用直接失效,并可能触发 Warning: Cannot modify header information。
- 实时输出常用
ob_implicit_flush(true)+ob_end_flush()或手动ob_flush()/flush(),但这些操作本身就会触发响应头发送 - Apache 的
mod_deflate、Nginx 的gzip、PHP-FPM 的缓冲区都可能截住输出,导致 CORS 头未及时生效 - 浏览器只检查第一个响应块的响应头,后续 chunk 不再校验 CORS,所以首块必须含完整 CORS 头
实操:确保首 chunk 包含有效 CORS 头
核心是「先发头,再发流」,且全程绕过中间层缓冲干扰:
- 开头立即设置:
header('Access-Control-Allow-Origin: https://your-frontend.com');(避免用*配合 credentials) - 关闭 PHP 输出缓冲:
if (ob_get_level()) ob_end_clean();,再调用ini_set('output_buffering', 'off')和ini_set('zlib.output_compression', 'Off') - 禁用 Web 服务器压缩:Nginx 中该 location 下加
gzip off;;Apache 加SetEnv no-gzip 1 - 输出前先发一个带换行的空块(防某些客户端卡住):
echo ":\n"; flush(); ob_flush();,再开始真实数据流
常见踩坑点:SSE 和 fetch 流式响应的兼容差异
用 text/event-stream 做实时推送时,CORS 行为和普通 fetch 不同:
立即学习“PHP免费学习笔记(深入)”;
- SSE 要求
Access-Control-Allow-Origin不能为*(除非不带 credentials),且必须显式声明Access-Control-Allow-Credentials: true - fetch +
Response.body.getReader()流读取时,若服务端首 chunk 没有 CORS 头,整个流会被浏览器静默中断,控制台无错误提示 - Chrome 对流式响应的 CORS 校验更严格——即使 header 正确,若首 chunk 小于 ~1KB,某些版本会延迟触发 preflight 或误判失败
最稳的做法:用 cURL 或 file_get_contents 在服务端代理请求,避开浏览器 CORS 限制;或者改用 WebSocket,它本就不受 CORS 约束。











