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

PHP header() 函數深度解析:HTTP 標頭控制、重定向與快取策略完整指南

     編輯:PHP 綜合知識

前言

在 PHP 開發中,header() 函數是控制 HTTP 回應標頭的核心工具。無論是實現頁面重定向、設定快取策略、觸發檔案下載,還是回傳特定 HTTP 狀態碼,都離不開它。本文將系統整理 header() 的進階用法、常見陷阱與最佳實踐,幫助開發者精準掌握 HTTP 標頭控制的藝術。

一、核心機制:最後一個生效的原理與條件

許多開發者知道「多個相同 header() 以最後一個為準」,但忽略了前置條件:前面的標頭必須尚未被實際發送。一旦有任何輸出(包含空白字元、BOM、echo 等),標頭即鎖定無法修改。

<?php
// 情況 A:無輸出干擾,最終跳轉至 baidu.com
header('Location: https://www.jb51.net');
header('Location: https://www.g.cn');
header('Location: https://www.baidu.com');

// 情況 B:第一行輸出空字串,導致標頭提前發送,最終跳轉至 g.cn
header('Location: https://www.jb51.net');
echo ''; // 關鍵:任何輸出都會刷新標頭緩衝區
header('Location: https://www.g.cn');
header('Location: https://www.baidu.com');
?>

最佳實踐:在所有 header() 呼叫前確保零輸出,並在重定向後立即執行 exit; 防止後續程式碼執行。

二、HTTP 協議基礎:請求/回應模型與標頭分類

2.1 通訊流程

HTTP 採用請求/回應範式:客戶端(瀏覽器/爬蟲)建立連線 → 發送請求行 + 標頭 + 主體 → 伺服器回應狀態行 + 標頭 + 主體 → 連線關閉(HTTP/1.1 預設 Keep-Alive)。

2.2 三大傳統單一標頭

根據 RFC 2616,以下標頭在傳統規範中只能出現一次:

  • Location: <URI> — 重定向目標
  • Content-Type: <MIME-type> — 實體內容類型
  • Status: <code> <reason> — 回應狀態(CGI 模式專用)

現代 Multipart MIME 規範允許同名標頭重複(如多個 Set-Cookie),但上述三者在單一回應中仍建議唯一。

三、HTTP 狀態碼速查表

分類範圍含義常見代碼
資訊回應1xx請求已接收,繼續處理100 Continue
成功回應2xx請求成功被接收、理解、接受200 OK、201 Created、204 No Content
重定向3xx需進一步行動以完成請求301 永久移動、302 臨時移動、304 未修改
客戶端錯誤4xx請求語法錯誤或無法滿足400 Bad Request、401 Unauthorized、403 Forbidden、404 Not Found
伺服器錯誤5xx伺服器無法完成合法請求500 Internal Server Error、502 Bad Gateway、503 Service Unavailable

四、實戰操作範例庫

4.1 標準重定向(最常用)

<?php
header('Location: https://www.php.net');
exit; // 強制終止腳本,避免後續輸出干擾
?>

4.2 禁用快取:強制瀏覽器每次抓取最新內容

<?php
// 1. 設定過期時間為過去日期
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');

// 2. 標示最後修改時間為「現在」
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');

// 3. HTTP/1.1 標準快取控制
header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
header('Cache-Control: post-check=0, pre-check=0', false); // 相容 IE

// 4. HTTP/1.0 相容
header('Pragma: no-cache');

// 5. 若為檔案下載,補充 Content-Disposition
// header('Content-Disposition: attachment; filename="report.xlsx"');
?>

關鍵差異:no-store 禁止任何儲存(含磁碟),no-cache 允許儲存但每次需向伺服器驗證。生產環境建議兩者合用。

4.3 回傳自訂 HTTP 狀態碼(權限控制、SEO 優化)

<?php
// 401 未授權 — 觸發瀏覽器彈出登入框
header('HTTP/1.1 401 Unauthorized');
header('WWW-Authenticate: Basic realm="Admin Area"');
exit;

// 404 未找到 — 隱藏真實路徑、誤導掃描器
header('HTTP/1.1 404 Not Found');
header('Status: 404 Not Found'); // CGI/FastCGI 相容
// 可選:include('404.html'); exit;
?>

4.4 檔案下載強制另存新檔

<?php
$filePath = '/data/exports/report_2024.xlsx';
$fileName = '年度報表_2024.xlsx';

if (!is_file($filePath)) {
    header('HTTP/1.1 404 Not Found');
    exit('檔案不存在');
}

header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
header('Content-Length: ' . filesize($filePath));
header('Content-Disposition: attachment; filename="' . rawurlencode($fileName) . '"');
header('Accept-Ranges: bytes');
readfile($filePath); // 高效輸出大檔,避免記憶體耗盡
exit;
?>

五、常見坑點與避雷指南

  1. BOM 檔案編碼:UTF-8 with BOM 會在檔案最開頭輸出 3 個隱形字元,導致 header() 失效。請儲存為「UTF-8 無 BOM」。
  2. 錯誤訊息輸出:warning/notice 會輸出內容。開發階段開啟 error_reporting(E_ALL),上線前設定 display_errors=Off 並記錄至日誌。
  3. 多重重定向迴圈:A→B→A 會導致瀏覽器報錯「重定向次數過多」。建議在重定向前檢查 $_SERVER['HTTP_REFERER'] 或使用 Session 標記。
  4. 大小寫敏感:HTTP 標頭名稱不分大小寫,但慣例採用 Content-Type、Location 等 Pascal-Case 風格。

六、現代替代方案:PSR-7 / Symfony HttpFoundation

在現代框架(Laravel、Symfony、Slim)中,建議使用標準化的 Response 物件:

// Laravel 範例
return response()->json($data, 200, ['X-Custom-Header' => 'value'])
    ->header('Cache-Control', 'no-cache, private');

// 原生 PSR-7 範例
use Nyholm\Psr7\Response;
$response = new Response(200, ['Content-Type' => 'application/json'], json_encode($data));
$response = $response->withHeader('Cache-Control', 'no-cache');

優點:可測試性高、避免「標頭已發送」錯誤、支援中介軟體管線。

七、總結

header() 是 PHP 與 HTTP 協議溝通的橋樑。掌握其「零輸出前置條件」、「單一標頭唯一性」、「快取控制組合拳」與「狀態碼語義」,能讓你精準控制瀏覽器行為、優化 SEO、強化安全性。下一步建議深入研讀 RFC 7231 與 RFC 7234,建立更堅實的 HTTP 知識體系。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved