使用者點擊按鈕觸發長時間任務(如匯出報表、發送大量郵件),希望瀏覽器立即收到「任務已啟動」回應,伺服器背景繼續執行。
| 方案 | 原理 | 適用場景 | 注意事項 |
|---|---|---|---|
ob_flush() + flush() | 輸出緩衝區內容到瀏覽器,但連線保持開啟 | 即時進度條、串流輸出 | 需關閉壓縮(zlib.output_compression=Off),Nginx/Apache 可能仍緩衝 |
fastcgi_finish_request() | PHP-FPM 專用,立即發送回應給客戶端,釋放連線,腳本繼續執行 | 背景任務、非阻塞回應 | 僅 PHP-FPM (FastCGI) 環境可用,CLI 模式無效 |
忽略用戶中斷 ignore_user_abort(true) + set_time_limit(0) | 即使瀏覽器關閉,腳本仍在背景執行 | 長時間獨立任務 | 需自行管理程程序生命週期、避免重複執行 |
| 任務隊列 | 將任務寫入 Redis/RabbitMQ/Database,Worker 進程消費 | 生產環境、高併發、可靠性要求高 | 架構較複雜,需部署 Worker、監控、重試機制 |
<?php
// 1. 準備回應資料
$response = ['status' => 'started', 'message' => '任務已在背景執行'];
// 2. 輸出並結束請求
header('Content-Type: application/json');
echo json_encode($response);
fastcgi_finish_request(); // 關鍵:此行後瀏覽器收到回應,PHP 繼續往下執行
// 3. 背景任務(不阻塞回應)
ignore_user_abort(true);
set_time_limit(0);
sleep(5); // 模擬耗時操作
file_put_contents(__DIR__ . '/task.log', date('Y-m-d H:i:s') . " 背景任務完成\n", FILE_APPEND);
// 實際可執行:匯出 Excel、發送郵件、呼叫 API 等
?>
# nginx.conf / vhost.conf
location ~ \.php$ {
fastcgi_pass unix:/run/php/php8.1-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
# 關閉 fastcgi 緩衝,確保 flush 即時生效
fastcgi_buffering off;
}
fastcgi_finish_request 無效。session_write_close() 釋放鎖,否則同用戶後續請求會阻塞。memory_limit,必要時 ini_set('memory_limit', '512M')。對於「立即回應、背景執行」需求,fastcgi_finish_request() 是 PHP-FPM 環境下最簡潔有效的方案。生產系統建議導入任務隊列(如 Laravel Queue、Symfony Messenger)以獲得更好的可靠性與擴展性。