首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP 實時輸出到瀏覽器:Chunked Transfer Encoding 與 ob_flush/flush 深度解析

     編輯:PHP 相關知識

為什麼需要實時輸出

  • 首屏加速:先輸出 <head> 含 CSS/JS,瀏覽器可並行下載靜態資源,不必等待完整 HTML 生成 (Yahoo 最佳實踐 #Flush the Buffer Early)。
  • 長耗時任務進度反饋:導出大報表、視頻轉碼、批量郵件發送等,逐步輸出進度條/日志。
  • 流式 API / SSE:實現 Server-Sent Events 或簡易流式 JSON 輸出。

HTTP/1.1 Chunked Transfer Encoding 原理

響應頭包含 Transfer-Encoding: chunked,Body 格式:


HTTP/1.1 200 OK
Transfer-Encoding: chunked
Content-Type: text/html; charset=utf-8

1\r\n
a\r\n
4\r\n
test\r\n
0\r\n
\r\n
  • 每塊:十六進制長度\r\n數據\r\n
  • 結束塊:0\r\n\r\n

PHP 實現方式

<?php
// 1. 禁用所有緩衝
@ini_set('output_buffering', 'Off');
@ini_set('zlib.output_compression', 'Off');

// 2. 發送頭信息 (可選,PHP 會自動添加 Transfer-Encoding: chunked)
header('Content-Type: text/html; charset=utf-8');

// 3. 輸出首屏關鍵資源
echo '<html><head><link rel="stylesheet" href="style.css"></head><body>';
echo '<h1>開始處理...</h1>';

// 關鍵:強制刷新到客戶端
ob_flush(); // 刷新 PHP output buffer
flush();    // 刷新 Web Server (Apache/Nginx) buffer

// 4. 模擬耗時任務
for ($i = 1; $i <= 10; $i++) {
    sleep(1); // 模擬耗時
    echo "<p>步驟 $i 完成</p>";
    ob_flush();
    flush();
}

echo '</body></html>';
ob_flush();
flush();

多層緩衝鏈路與失效排查

層級組件控制函數/配置常見失效原因
1PHP output_bufferingob_start() / ob_flush() / ini_set('output_buffering', 0)php.ini 強制開啟 output_buffering=4096
2PHP zlib 壓縮zlib.output_compression開啟後需等壓縮塊滿才輸出,Chunked 下無法逐塊壓縮
3Web Server (Apache mod_php)flush()Apache 模塊模式下 flush() 有效
4FastCGI (PHP-FPM)ob_flush()Nginx fastcgi_buffering on (默認) 會緩衝整個響應
5Nginx Proxyproxy_buffering off;默認開啟緩衝,需在 location 關閉
6瀏覽器渲染—IE/Edge/Chrome 需接收 ≥256-1024 字節才開始渲染,Firefox 即時

Nginx + PHP-FPM 生產環境必改配置

# nginx.conf / location 塊
fastcgi_buffering off;        # 關閉 FastCGI 緩衝
proxy_buffering off;          # 若有反向代理再關閉 proxy 緩衝
gzip off;                     # 實時輸出場景關閉 gzip,或用 chunked gzip (需 Nginx 1.13.9+)

瀏覽器最小渲染閾值測試

<?php
// 測試不同瀏覽器何時顯示內容
for ($i = 0; $i < 20; $i++) {
    echo str_repeat(' ', 50); // 填充字節
    echo "<!-- chunk $i -->\n";
    ob_flush(); flush();
    usleep(200000);
}

經驗值:Chrome/Edge 約 1KB,Firefox 即時,Safari 約 512B。可在 <body> 開頭輸出 <!-- padding --> 觸發渲染。

最佳實踐清單

  1. 入口文件最頂部 @ini_set('output_buffering', 'Off'); @ini_set('zlib.output_compression', 'Off');
  2. 2. 同時調用 ob_flush(); flush(); 兼容 Apache/Nginx。 3. Nginx 必須 fastcgi_buffering off;。 4. 輸出前填充 ≥1024 字節 (空白/註釋) 觸發瀏覽器渲染。 5. 異常處理:register_shutdown_function 確保關閉標簽輸出。 6. 大文件下載/導出改用 readfile() + X-Sendfile / X-Accel-Redirect 卸載 PHP 進程。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved