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

PHP 串流模擬 HTTP 請求:cURL 與 Stream Context 雙方案實戰

     編輯:PHP 相關知識

應用場景

第三方 API 整合 (如 Facebook Graph API)、微服務間通訊、Webhook 回調、爬蟲抓取等需發送 HTTP 請求的場景。

方案一:cURL (推薦,功能完整、效能優)

<?php
function httpRequestWithCurl($url, $postData = [], $headers = [], $options = []) {
    if (!function_exists('curl_init')) {
        throw new RuntimeException('cURL 擴展未安裝');
    }
    
    $ch = curl_init();
    
    $defaultOptions = [
        CURLOPT_URL => $url,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT => 30,
        CURLOPT_CONNECTTIMEOUT => 10,
        CURLOPT_SSL_VERIFYPEER => true,  // 生產環境必須驗證
        CURLOPT_FOLLOWLOCATION => true,
        CURLOPT_MAXREDIRS => 5,
        CURLOPT_USERAGENT => 'MyApp/1.0 (PHP/' . PHP_VERSION . ')',
    ];
    
    // POST 資料處理
    if (!empty($postData)) {
        $defaultOptions[CURLOPT_POST] = true;
        $defaultOptions[CURLOPT_POSTFIELDS] = is_array($postData) 
            ? http_build_query($postData) 
            : $postData;
    }
    
    // 自訂標頭
    if (!empty($headers)) {
        $defaultOptions[CURLOPT_HTTPHEADER] = array_map(
            fn($k, $v) => "$k: $v", 
            array_keys($headers), 
            array_values($headers)
        );
    }
    
    // 合併使用者選項
    curl_setopt_array($ch, array_merge($defaultOptions, $options));
    
    $response = curl_exec($ch);
    $error = curl_error($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);
    
    if ($error) {
        throw new RuntimeException("cURL 錯誤: $error");
    }
    
    return [
        'body' => $response,
        'http_code' => $httpCode,
        'info' => curl_getinfo($ch)
    ];
}

// 使用範例
$url = "https://graph.facebook.com/v18.0/me/friends";
$postData = ['access_token' => 'USER_ACCESS_TOKEN'];
$result = httpRequestWithCurl($url, $postData);
var_dump($result);
?>

方案二:Stream Context (原生、無依賴、適合簡單場景)

<?php
function httpRequestWithStream($url, $postData = [], $headers = [], $options = []) {
    $contextOptions = [
        'http' => array_merge([
            'method' => empty($postData) ? 'GET' : 'POST',
            'timeout' => 30,
            'ignore_errors' => true,  // 獲取 4xx/5xx 回應內容
            'follow_location' => 1,
            'max_redirects' => 5,
            'user_agent' => 'MyApp/1.0 (PHP/' . PHP_VERSION . ')',
        ], $options)
    ];
    
    if (!empty($postData)) {
        $content = is_array($postData) ? http_build_query($postData) : $postData;
        $contextOptions['http']['content'] = $content;
        $contextOptions['http']['header'][] = 'Content-Type: application/x-www-form-urlencoded';
        $contextOptions['http']['header'][] = 'Content-Length: ' . strlen($content);
    }
    
    if (!empty($headers)) {
        foreach ($headers as $key => $value) {
            $contextOptions['http']['header'][] = "$key: $value";
        }
    }
    
    $context = stream_context_create($contextOptions);
    
    // 使用檔案操作函數發送請求
    $response = @file_get_contents($url, false, $context);
    
    // 取得 HTTP 狀態碼 (需 PHP 5.3.4+)
    $httpCode = 0;
    if (isset($http_response_header)) {
        preg_match('/HTTP\/\d\.\d\s+(\d+)/', $http_response_header[0], $matches);
        $httpCode = (int)($matches[1] ?? 0);
    }
    
    if ($response === false) {
        $error = error_get_last();
        throw new RuntimeException("Stream 請求失敗: " . ($error['message'] ?? 'Unknown'));
    }
    
    return [
        'body' => $response,
        'http_code' => $httpCode,
        'headers' => $http_response_header ?? []
    ];
}

// 使用範例
$url = "https://api.example.com/endpoint";
$headers = ['Authorization' => 'Bearer TOKEN'];
$result = httpRequestWithStream($url, [], $headers);
var_dump($result);
?>

兩者對比選擇指南

特性cURLStream Context
依賴需安裝擴展PHP 內建
協定支援HTTP/HTTPS/FTP/SMTP/IMAP 等HTTP/HTTPS/FTP
效能高 (持久連線、多執行緒)中等
功能豐富度完整 (代理、憑證、Cookie、斷點續傳)基礎
錯誤處理詳細錯誤代碼/訊息較簡略
適用場景生產環境、複雜需求、高併發簡單請求、無 cURL 環境、快速原型

進階:統一介面封裝 (策略模式)

<?php
interface HttpClientInterface {
    public function request(string $url, array $data = [], array $headers = []): array;
}

class CurlClient implements HttpClientInterface {
    public function request(string $url, array $data = [], array $headers = []): array {
        // 實現 cURL 邏輯...
    }
}

class StreamClient implements HttpClientInterface {
    public function request(string $url, array $data = [], array $headers = []): array {
        // 實現 Stream 邏輯...
    }
}

class HttpClientFactory {
    public static function create(): HttpClientInterface {
        return function_exists('curl_init') ? new CurlClient() : new StreamClient();
    }
}

// 使用
$client = HttpClientFactory::create();
$response = $client->request('https://api.example.com', ['key' => 'value']);
?>

安全與最佳實踐

  • 永遠驗證 SSL 憑證:生產環境 CURLOPT_SSL_VERIFYPEER = true
  • 設定超時:連線與讀取超時雙重保護
  • 敏感資訊不記錄:Token、密碼過濾後再記錄日誌
  • 冪等性設計:GET/HEAD/PUT/DELETE 應可安全重試
  • 熔斷機制:整合 Circuit Breaker 防止雪崩效應
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved