17370845950

php实时输出ios端兼容吗_php实时输出ios适配法【技巧】
iOS Safari 实时输出需服务端禁用缓冲、首块≥1KB、Nginx关prox

y_buffering,客户端用fetch+ReadableStream逐chunk解码;否则ob_flush()+flush()无效。

PHP 实时输出在 iOS Safari 上默认不生效,必须配合特定响应头、缓冲控制和客户端处理才能工作。

为什么 ob_flush() + flush() 在 iOS 上经常“没反应”

iOS Safari(包括微信内置浏览器)对流式响应极其保守:它会等待足够多数据(通常 ≥ 1KB)或遇到完整 HTTP 响应头后才开始解析,且默认启用代理级缓冲(如 Cloudflare、CDN 或 Nginx 的 proxy_buffering on)。单纯调用 ob_flush()flush() 几乎无效。

  • 必须禁用 PHP 输出缓冲链:ob_end_clean() 或全程关闭 output_buffering
  • 需发送明确的 Content-TypeTransfer-Encoding: chunked(由服务器自动添加,但需确保不被中间件覆盖)
  • 首块输出建议 ≥ 1024 字节(可用空格/注释填充),绕过 iOS 的初始缓冲阈值
  • Nginx 需显式关闭代理缓冲:proxy_buffering off;,并设置 chunked_transfer_encoding on;

PHP 端最小可行实时输出代码(iOS 兼容)

以下代码在 CLI 模式下不可用,仅适用于 Web SAPI(如 FPM),且依赖服务端配置配合:

注意:sleep() 仅用于演示;生产中应替换为实际耗时逻辑(如 API 调用、数据库轮询)。

iOS 客户端必须用 fetch() + ReadableStream 接收

XMLHttpRequest 不支持流式读取;iOS Safari 16.4+ 才稳定支持 Response.body.getReader()。必须用 fetch 并手动解析 chunk:

  • 不能用 response.text() —— 它会等全部响应结束
  • 需逐 chunk 解码:decoder.decode(chunk, {stream: true}),否则中文乱码
  • 要主动检查 done 标志,避免死循环
  • 推荐使用 text-encoding polyfill 或原生 TextDecoder

简易 JS 接收示例:

const decoder = new TextDecoder('utf-8');
const response = await fetch('/stream.php');
const reader = response.body.getReader();

while (true) {
    const { done, value } = await reader.read();
    if (done) break;
    const text = decoder.decode(value, { stream: true });
    console.log(text); // 或更新 DOM
}

真正卡住的地方往往不在 PHP 代码里

最常被忽略的是部署层:Nginx 默认开启 proxy_buffering,且很多 CDN(如 Cloudflare)强制缓冲整个响应;PHP-FPM 的 buffer_output 也可能开启;甚至某些 iOS 微信版本会拦截非 HTTPS 的流式请求。验证是否生效,最直接的方式是用 Safari 开发者工具 → Network → 查看响应的 Content-Length 是否为 chunked,且 Timeline 中有持续的“接收中”状态。没有这个,前端再怎么写 fetch 也收不到实时数据。