瀏覽器同源策略攔截非同源請求。本地文件 (file:// 或 localhost:8080) 請求 API (api.example.com) 觸發 CORS 錯誤:
No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access.
非簡單請求 (含自定義 Header、非 GET/POST/HEAD、Content-Type 非表單類型) 會先發送 OPTIONS 請求詢問服務器是否允許跨域。
<?php
// 必須在任何輸出前設置
header('Access-Control-Allow-Origin: *'); // 或具體域名: https://a.example.com
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'); // 預檢緩存 24 小時
// 處理 OPTIONS 預檢請求直接返回
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
exit(0);
}
// 正常業務邏輯...
echo json_encode(['status' => 'ok', 'data' => [...]]);
| Header | 作用 | 示例 |
|---|---|---|
| Access-Control-Allow-Origin | 允許的源 (* 或單一域名) | * / https://a.com |
| Access-Control-Allow-Methods | 允許的 HTTP 方法 | GET, POST, OPTIONS |
| Access-Control-Allow-Headers | 允許的請求頭 | Content-Type, Authorization |
| Access-Control-Allow-Credentials | 是否允許攜帶 Cookie | true (需 Origin 非 *) |
| Access-Control-Max-Age | 預檢結果緩存秒數 | 86400 |
| Access-Control-Expose-Headers | 允許 JS 讀取的響應頭 | X-Total-Count |
header('Access-Control-Allow-Origin: https://a.example.com'); // 不能用 *
header('Access-Control-Allow-Credentials: true');
前端 AJAX 設置 xhr.withCredentials = true 或 fetch(..., {credentials: 'include'})。
# Nginx
location /api/ {
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
add_header Access-Control-Allow-Headers 'Content-Type, Authorization';
if ($request_method = OPTIONS) { return 204; }
proxy_pass https://php_backend;
}
CORS 核心在服務器響應頭,PHP 中用 header() 設置,必須在輸出前。生產環境建議:具體域名而非 *、配置允許憑證、Nginx 統一處理 避免代碼入侵。理解預檢機制有助於排查疑難跨域問題。