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

PHP cURL 設定請求標頭與獲取回應標頭完整指南

     編輯:PHP 綜合知識

前言:HTTP 標頭操作的核心場景

無論是串接第三方 API、實現反向代理、模擬瀏覽器行為、或是進行安全測試,精確控制 HTTP 請求標頭與解析回應標頭都是 PHP 開發者的必備技能。本文系統梳理 cURL 標頭操作全流程。

核心 cURL 選項速查表

選項用途典型值
CURLOPT_HTTPHEADER設定請求標頭陣列['Content-Type: application/json', 'Authorization: Bearer xxx']
CURLOPT_HEADER是否將回應標頭包含在輸出中1 (包含) / 0 (不包含,預設)
CURLOPT_HEADERFUNCTION自定義回應標頭處理回呼function($ch, $header) { ... return strlen($header); }
CURLINFO_HEADER_OUT啟用後可透過 curl_getinfo 獲取實際發送的請求標頭1

實戰一:發送自定義請求標頭

function sendWithCustomHeaders(string $url, array $headers, string $body = ''): array {
    $ch = curl_init($url);
    
    curl_setopt_array($ch, [
        CURLOPT_POST => true,
        CURLOPT_POSTFIELDS => $body,
        CURLOPT_HTTPHEADER => $headers,           // 關鍵:設定請求標頭
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_HEADER => true,                   // 關鍵:回應包含標頭
        CURLOPT_SSL_VERIFYPEER => false,          // 僅測試環境使用
        CURLOPT_TIMEOUT => 10,
    ]);
    
    $response = curl_exec($ch);
    $errno = curl_errno($ch);
    $error = curl_error($ch);
    $info = curl_getinfo($ch);
    curl_close($ch);
    
    if ($errno) {
        throw new RuntimeException("cURL 錯誤 ($errno): $error");
    }
    
    // 分離標頭與主體
    $headerSize = $info['header_size'];
    $responseHeaders = substr($response, 0, $headerSize);
    $responseBody = substr($response, $headerSize);
    
    return [
        'status' => $info['http_code'],
        'headers' => parseRawHeaders($responseHeaders),
        'body' => $responseBody,
        'sent_headers' => $info['request_header'] ?? null, // 需啟用 CURLINFO_HEADER_OUT
    ];
}

function parseRawHeaders(string $raw): array {
    $headers = [];
    foreach (explode("\r\n", $raw) as $line) {
        if (strpos($line, ':') !== false) {
            [$key, $value] = explode(':', $line, 2);
            $key = strtolower(trim($key));
            $headers[$key] = trim($value);
        }
    }
    return $headers;
}

// 使用範例
$headers = [
    'Content-Type: application/json',
    'Authorization: Bearer ' . $accessToken,
    'X-Request-ID: ' . uniqid('req_', true),
    'Accept: application/json',
];
$result = sendWithCustomHeaders('https://api.example.com/v1/users', $headers, json_encode(['name' => 'John']));
print_r($result['headers']);

實戰二:獲取並解析回應標頭(含 Set-Cookie)

function fetchHeadersOnly(string $url): array {
    $ch = curl_init($url);
    curl_setopt_array($ch, [
        CURLOPT_NOBODY => true,        // HEAD 請求,不下載主體
        CURLOPT_HEADER => true,        // 獲取標頭
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_FOLLOWLOCATION => true, // 跟隨重定向
        CURLOPT_TIMEOUT => 10,
    ]);
    $headerData = curl_exec($ch);
    curl_close($ch);
    return parseRawHeaders($headerData);
}

// 解析 Set-Cookie 多值標頭
function parseSetCookie(string $rawHeaders): array {
    $cookies = [];
    if (preg_match_all('/^Set-Cookie:\s*(.+)$/mi', $rawHeaders, $matches)) {
        foreach ($matches[1] as $cookieLine) {
            parse_str($cookieLine, $parts); // 簡易解析,實際建議用專門庫
            $cookies[] = $parts;
        }
    }
    return $cookies;
}

實戰三:模擬瀏覽器完整請求(含 Cookie Jar)

class BrowserSimulator {
    private $ch;
    private $cookieFile;
    
    public function __construct() {
        $this->cookieFile = sys_get_temp_dir() . '/cookies_' . uniqid() . '.txt';
        $this->ch = curl_init();
        curl_setopt_array($this->ch, [
            CURLOPT_COOKIEJAR => $this->cookieFile,
            CURLOPT_COOKIEFILE => $this->cookieFile,
            CURLOPT_USERAGENT => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_SSL_VERIFYPEER => false,
            CURLOPT_TIMEOUT => 30,
        ]);
    }
    
    public function get(string $url, array $extraHeaders = []): array {
        curl_setopt($this->ch, CURLOPT_HTTPGET, true);
        curl_setopt($this->ch, CURLOPT_URL, $url);
        curl_setopt($this->ch, CURLOPT_HTTPHEADER, array_merge([
            'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
            'Accept-Language: zh-TW,zh;q=0.9,en;q=0.8',
        ], $extraHeaders));
        return $this->exec();
    }
    
    public function post(string $url, array $data, array $extraHeaders = []): array {
        curl_setopt($this->ch, CURLOPT_POST, true);
        curl_setopt($this->ch, CURLOPT_POSTFIELDS, http_build_query($data));
        curl_setopt($this->ch, CURLOPT_URL, $url);
        curl_setopt($this->ch, CURLOPT_HTTPHEADER, array_merge([
            'Content-Type: application/x-www-form-urlencoded',
            'Origin: ' . parse_url($url, PHP_URL_SCHEME) . '://' . parse_url($url, PHP_URL_HOST),
            'Referer: ' . $url,
        ], $extraHeaders));
        return $this->exec();
    }
    
    private function exec(): array {
        $response = curl_exec($this->ch);
        $info = curl_getinfo($this->ch);
        if (curl_errno($this->ch)) {
            throw new RuntimeException(curl_error($this->ch));
        }
        $headerSize = $info['header_size'];
        return [
            'status' => $info['http_code'],
            'headers' => parseRawHeaders(substr($response, 0, $headerSize)),
            'body' => substr($response, $headerSize),
            'effective_url' => $info['url'],
        ];
    }
    
    public function __destruct() {
        curl_close($this->ch);
        @unlink($this->cookieFile);
    }
}

常見坑點與解決方案

問題原因解決
自定義 Host 標頭無效cURL 自動從 URL 解析 Host使用 `CURLOPT_RESOLVE` 指定 IP 映射,或配合 `CURLOPT_HTTPHEADER` 設定 Host
Content-Length 重複同時設定 POSTFIELDS 與 Content-Length勿手動設定 Content-Length,cURL 自動計算
回應標頭中文亂碼伺服器未指定 charset 或編碼不一致使用 `mb_detect_encoding` + `iconv` 轉換
大檔案下載記憶體爆炸CURLOPT_RETURNTRANSFER 緩存整個主體使用 `CURLOPT_WRITEFUNCTION` 流式寫入檔案

進階:非同步併發請求(cURL Multi)

function multiRequest(array $urls, int $maxConcurrent = 10): array {
    $mh = curl_multi_init();
    $handles = [];
    $results = [];
    
    foreach ($urls as $i => $url) {
        $ch = curl_init($url);
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_HEADER => true,
            CURLOPT_TIMEOUT => 10,
        ]);
        curl_multi_add_handle($mh, $ch);
        $handles[$i] = $ch;
    }
    
    $running = null;
    do {
        curl_multi_exec($mh, $running);
        curl_multi_select($mh, 0.5);
    } while ($running > 0);
    
    foreach ($handles as $i => $ch) {
        $response = curl_multi_getcontent($ch);
        $info = curl_getinfo($ch);
        $headerSize = $info['header_size'];
        $results[$i] = [
            'url' => $urls[$i],
            'status' => $info['http_code'],
            'headers' => parseRawHeaders(substr($response, 0, $headerSize)),
            'body' => substr($response, $headerSize),
        ];
        curl_multi_remove_handle($mh, $ch);
        curl_close($ch);
    }
    curl_multi_close($mh);
    return $results;
}

結語

掌握 cURL 標頭操作,能讓你從容應對 API 串接、爬蟲開發、微服務通訊、安全測試等場景。建議封裝為可複用的 HTTP Client 類別,整合 PSR-18 標準,提升專案可維護性。

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