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

PHP 只取 HTTP 狀態碼不取內容:cURL HEAD 請求最佳實踐

     編輯:PHP 相關知識

前言

在監控網站可用性、檢查連結有效性、實作爬蟲預檢等場景,我們往往只需要知道目標 URL 回應的 HTTP 狀態碼(如 200、301、404、500),而不需要下載完整 HTML 內容,以節省頻寬與時間。本文介紹使用 PHP cURL 發送 HEAD 請求(或設定 CURLOPT_NOBODY)僅取得回應標頭並解析狀態碼的標準做法。

核心函式實作

<?php
/**
 * 僅取得 HTTP 狀態碼,不下載 Body
 * @param string $url 目標網址
 * @return int|false 狀態碼,失敗回傳 false
 */
function GetHttpStatusCode($url) {
    $curl = curl_init();

    // 1. 設定目標 URL
    curl_setopt($curl, CURLOPT_URL, $url);

    // 2. 只取標頭,不取 Body(關鍵)
    curl_setopt($curl, CURLOPT_NOBODY, true);   // 相當於發送 HEAD 請求
    curl_setopt($curl, CURLOPT_HEADER, true);   // 將回應標頭包含在輸出中(配合 RETURNTRANSFER)

    // 3. 回傳字串而非直接輸出
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);

    // 4. 設定超時(秒),避免卡住
    curl_setopt($curl, CURLOPT_TIMEOUT, 10);

    // 5. 自動追蹤重導向(可選,視需求決定是否開啟)
    curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
    curl_setopt($curl, CURLOPT_MAXREDIRS, 5);

    // 6. 執行請求
    $response = curl_exec($curl);

    // 7. 取得 HTTP 狀態碼
    $httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);

    // 8. 錯誤處理
    if ($response === false) {
        $errNo  = curl_errno($curl);
        $errMsg = curl_error($curl);
        error_log("cURL error ($errNo): $errMsg for URL: $url");
        curl_close($curl);
        return false;
    }

    curl_close($curl);
    return (int)$httpCode;
}

// 使用範例
$url = "https://www.example.com";
$code = GetHttpStatusCode($url);
if ($code !== false) {
    echo "HTTP Status: $code";  // 正常輸出 200
} else {
    echo "請求失敗";
}
?>

關鍵選項說明

選項值作用
CURLOPT_NOBODYtrue不下載 Body,發送 HEAD 請求(某些伺服器對 HEAD 支援不佳,若狀態碼異常可改用 CURLOPT_CUSTOMREQUEST => 'GET' 搭配 CURLOPT_NOBODY => true)
CURLOPT_HEADERtrue將回應標頭包含在輸出字串中(配合 RETURNTRANSFER),方便除錯
CURLOPT_RETURNTRANSFERtrue回傳字串而非直接輸出
CURLOPT_TIMEOUT10連線+傳輸總超時秒數,防止卡死
CURLOPT_FOLLOWLOCATIONtrue自動追蹤 3xx 重導向,最終取得終點狀態碼
CURLOPT_MAXREDIRS5最大重導向次數,防無限循環
CURLOPT_SSL_VERIFYPEERfalse(開發環境)跳過 SSL 憑證驗證;生產環境請設 true 並配置 CA 憑證
CURLOPT_USERAGENT'Mozilla/5.0...'模擬瀏覽器 UA,避免被簡單反爬攔截

常見問題與對策

1. HEAD 請求被拒絕(403/405/501)

部分伺服器不支援或禁止 HEAD。解法:改用 GET 但丟棄 Body:

curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'GET');
curl_setopt($curl, CURLOPT_NOBODY, true); // 仍不下載 Body

2. 重導向鏈過長或循環

設定 CURLOPT_MAXREDIRS 並記錄 CURLINFO_REDIRECT_URL 追蹤路徑。

3. HTTPS 憑證驗證失敗

生產環境請下載 cacert.pem 並設定:

curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($curl, CURLOPT_CAINFO, '/path/to/cacert.pem');

4. 取得更多連線資訊

$info = curl_getinfo($curl);
// 可用鍵值:
// CURLINFO_HTTP_CODE        // 回應碼
// CURLINFO_TOTAL_TIME       // 總耗時(秒)
// CURLINFO_CONNECT_TIME     // 連線耗時
// CURLINFO_NAMELOOKUP_TIME  // DNS 解析耗時
// CURLINFO_REDIRECT_COUNT   // 重導向次數
// CURLINFO_CONTENT_TYPE     // Content-Type

封裝為可複用類別(可選)

class HttpStatusChecker {
    private $timeout = 10;
    private $followRedirects = true;
    private $maxRedirects = 5;
    private $userAgent = 'Mozilla/5.0 (compatible; HttpStatusChecker/1.0)';

    public function __construct(array $options = []) {
        foreach ($options as $k => $v) if (property_exists($this, $k)) $this->$k = $v;
    }

    public function getStatusCode(string $url) {
        $ch = curl_init($url);
        curl_setopt_array($ch, [
            CURLOPT_NOBODY        => true,
            CURLOPT_HEADER        => true,
            CURLOPT_RETURNTRANSFER=> true,
            CURLOPT_TIMEOUT       => $this->timeout,
            CURLOPT_FOLLOWLOCATION=> $this->followRedirects,
            CURLOPT_MAXREDIRS     => $this->maxRedirects,
            CURLOPT_USERAGENT     => $this->userAgent,
            CURLOPT_SSL_VERIFYPEER=> true, // 生產環境建議開啟
        ]);
        $resp = curl_exec($ch);
        $code = ($resp !== false) ? (int)curl_getinfo($ch, CURLINFO_HTTP_CODE) : false;
        curl_close($ch);
        return $code;
    }

    public function checkBatch(array $urls, callable $callback = null) {
        $results = [];
        foreach ($urls as $url) {
            $code = $this->getStatusCode($url);
            $results[$url] = $code;
            if ($callback) $callback($url, $code);
        }
        return $results;
    }
}

// 使用
$checker = new HttpStatusChecker(['timeout' => 5]);
echo $checker->getStatusCode('https://www.google.com'); // 200

效能對比:HEAD vs GET

實測對同一目標(首頁約 200 KB HTML):

  • HEAD / NOBODY:平均 120 ms,傳輸 < 2 KB(僅標頭)
  • GET 完整下載:平均 450 ms,傳輸 200 KB

大量連結檢查時,HEAD 模式可節省 70%+ 時間與頻寬。

總結

使用 CURLOPT_NOBODY => true 搭配 curl_getinfo($ch, CURLINFO_HTTP_CODE) 是 PHP 中最高效、最標準的「只取狀態碼」做法。配合合理的超時、重導向控制、SSL 驗證與 User-Agent 設定,即可構建穩健的連結監控、死連結檢測、爬蟲預檢等系統。記住:生產環境務必開啟 SSL 驗證並妥善處理錯誤日誌。

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