header(string $header, bool $replace = true, int $response_code = 0): void
$replace:true 替換同類 Header(預設),false 允許多個同名 Header$response_code:強制設置 HTTP 響應碼(PHP 4.3+)<?php
// ❌ 錯誤:前面有空白/HTML/BOM
echo " ";
header('Location: /'); // Warning: Cannot modify header information
// ✅ 正確:無任何輸出前調用
header('Location: /');
exit;
解決方案:啟用 output_buffering(php.ini 或 ob_start()),或確保文件無 BOM、無前置輸出。
| 類別 | 碼 | 含義 | 典型場景 |
|---|---|---|---|
| 1xx | 100 | Continue | 大文件上傳預檢 |
| 101 | Switching Protocols | WebSocket 升級 | |
| 2xx | 200 | OK | 成功響應 |
| 201 | Created | POST 創建資源 | |
| 204 | No Content | DELETE 成功無內容 | |
| 3xx | 301 | Moved Permanently | 永久重定向(SEO 傳遞權重) |
| 302 | Found | 臨時重定向(預設 Location 行為) | |
| 304 | Not Modified | 緩存驗證(配合 ETag/Last-Modified) | |
| 307 | Temporary Redirect | 保持方法重定向 | |
| 308 | Permanent Redirect | 保持方法永久重定向 | |
| 4xx | 400 | Bad Request | 參數錯誤 |
| 401 | Unauthorized | 未登錄/Token 無效 | |
| 403 | Forbidden | 無權限 | |
| 404 | Not Found | 資源不存在 | |
| 422 | Unprocessable Entity | 驗證失敗(WebDAV/RFC 4918) | |
| 429 | Too Many Requests | 限流 | |
| 5xx | 500 | Internal Server Error | 代碼異常 |
| 502 | Bad Gateway | 上游服務失敗 | |
| 503 | Service Unavailable | 維護/過載 |
<?php
// 302 臨時重定向(預設)
header('Location: https://example.com/login');
exit;
// 301 永久重定向(SEO 友好)
header('Location: https://example.com/new-url', true, 301);
exit;
// 相對路徑轉絕對(HTTP/1.1 要求絕對 URI)
$base = "https://{$_SERVER['HTTP_HOST']}" . dirname($_SERVER['PHP_SELF']);
header("Location: {$base}/target.php");
exit;
<?php
// 完整禁用緩存組合拳
header('Cache-Control: no-cache, no-store, must-revalidate, max-age=0'); // HTTP/1.1
header('Pragma: no-cache'); // HTTP/1.0 兼容
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); // 過去日期
// 僅驗證緩存(配合 ETag)
header('Cache-Control: no-cache, must-revalidate');
header('ETag: "' . md5($content) . '"');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
<?php
$file = '/path/to/report.xlsx';
$filename = '報表_2024.xlsx';
if (!is_file($file)) {
http_response_code(404);
exit('文件不存在');
}
$size = filesize($file);
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
header('Content-Disposition: attachment; filename="' . rawurlencode($filename) . '"; filename*=UTF-8\'\'' . rawurlencode($filename));
header('Content-Length: ' . $size);
header('Accept-Ranges: bytes');
header('Cache-Control: private, max-age=0'); // 私有緩存,不經代理
readfile($file); // 高效輸出大文件
exit;
<?php
function jsonResponse(array $data, int $code = 200): void
{
http_response_code($code);
header('Content-Type: application/json; charset=utf-8');
header('X-Content-Type-Options: nosniff'); // 防 MIME 嗅探
echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
exit;
}
// 使用
jsonResponse(['status' => 'ok', 'data' => $users]);
jsonResponse(['error' => '驗證失敗'], 422);
<?php
// 簡單請求
header('Access-Control-Allow-Origin: https://app.example.com'); // 不要用 * 配合 credentials
header('Access-Control-Allow-Credentials: true');
header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization, X-Requested-With');
header('Access-Control-Max-Age: 86400'); // 預檢緩存 1 天
// 預檢請求直接返回
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
http_response_code(204);
exit;
}
<?php
header('X-Frame-Options: DENY'); // 禁止 iframe 嵌入
header('X-Content-Type-Options: nosniff'); // 禁用 MIME 嗅探
header('Referrer-Policy: strict-origin-when-cross-origin');
header('Content-Security-Policy: default-src \'self\'; script-src \'self\' https://cdn.example.com; style-src \'self\' \'unsafe-inline\';');
header('Strict-Transport-Security: max-age=31536000; includeSubDomains; preload'); // 僅 HTTPS
Location: 自動發送 302(除非已發送 3xx),必須配合 exit 防止後續代碼執行。HTTP/1.1 XXX 格式:直接設置狀態行,header('HTTP/1.1 404 Not Found')。header('Set-Cookie: a=1', false); header('Set-Cookie: b=2', false);($replace=false)。| 陷阱 | 症狀 | 解決 |
|---|---|---|
| BOM/空白輸出 | Warning: Cannot modify header | 文件存為 UTF-8 無 BOM;ob_start();檢查 include 文件 |
| 重定向後代碼繼續執行 | 邏輯錯誤、多次重定向 | header('Location:...'); exit; |
| 中文文件名下載亂碼 | 瀏覽器顯示亂碼 | rawurlencode() + filename*=UTF-8'' (RFC 5987) |
| 緩存頭未生效 | 瀏覽器仍緩存 | 檢查代理/CDN 緩存設置;確保 HTTPS 下 HSTS 不衝突 |
| 多次 session_start() 導致 Header 衝突 | Cookie 重複 | 用 session_status() 判斷 |
response()->json(), redirect(), download(), 中間件自動處理 CORS/安全頭Response 物件、HttpFoundation 組件$response->withHeader()、withStatus()精通 header() 的各類 HTTP 交互細節,是構建健壯 Web 應用、API、文件服務、安全防護的基石。始終記住:Header 先於 Body,狀態碼語義化,緩存策略顯式化,安全頭標準化。