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

PHP cURL Expect: 100-continue 問題解決方案

     編輯:PHP 綜合知識

問題現象

使用 cURL POST 資料時,若資料長度超過 1024 位元組,libcurl 會自動啟用 Expect: 100-continue 機制:

  1. 先發送含 Expect: 100-continue 標頭的請求,詢問伺服器是否願意接收資料
  2. 收到伺服器 100 Continue 回應後,才發送實際 POST 主體

此行為符合 HTTP/1.1 規範(RFC 2616 Section 8.2.3),但部分伺服器(如 Lighttpd、舊版 Nginx、某些代理)不支援或拒絕回應 100 Continue,導致請求掛起或回傳 417 Expectation Failed。

解決方法

在 curl_setopt 中設定空的 Expect: 標頭,禁用此機制:

<?php
$ch = curl_init('https://api.example.com/endpoint');

$postData = json_encode(['large' => 'data...']); // 超過 1024 bytes

curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => $postData,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Content-Type: application/json',
        'Expect:'  // 關鍵:空值覆蓋預設的 Expect: 100-continue
    ],
]);

$response = curl_exec($ch);
if ($response === false) {
    throw new Exception('cURL 錯誤: ' . curl_error($ch));
}
curl_close($ch);
?>

原理解析

  • CURLOPT_HTTPHEADER 允許覆蓋 libcurl 自動產生的標頭
  • 設定 'Expect:'(冒號後無值)會發送 Expect: 空標頭,依 HTTP 規範視為「不期望 100-continue 回應」
  • libcurl 將直接發送完整請求(標頭 + 主體),不再等待中間回應

替代方案:調整閾值(不推薦)

libcurl 內建閾值為 1024 位元組,無直接 API 修改。若必須保留 100-continue 機制,需確保目標伺服器正確支援。

完整除錯範例

<?php
function postWithCurl($url, $data, $headers = [], $timeout = 30) {
    $ch = curl_init($url);
    
    $defaultHeaders = [
        'Content-Type: application/json',
        'Expect:',  // 預設禁用 100-continue
    ];
    
    curl_setopt_array($ch, [
        CURLOPT_POST => true,
        CURLOPT_POSTFIELDS => is_array($data) ? json_encode($data) : $data,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT => $timeout,
        CURLOPT_CONNECTTIMEOUT => 10,
        CURLOPT_HTTPHEADER => array_merge($defaultHeaders, $headers),
        CURLOPT_SSL_VERIFYPEER => true,  // 生產環境請保持 true
        CURLOPT_FOLLOWLOCATION => true,
        CURLOPT_MAXREDIRS => 5,
    ]);
    
    $response = curl_exec($ch);
    $errno = curl_errno($ch);
    $error = curl_error($ch);
    $info = curl_getinfo($ch);
    curl_close($ch);
    
    if ($errno) {
        throw new Exception("cURL 錯誤 ($errno): $error");
    }
    
    if ($info['http_code'] >= 400) {
        throw new Exception("HTTP 錯誤 {$info['http_code']}: $response");
    }
    
    return $response;
}

// 使用範例
try {
    $result = postWithCurl('https://api.example.com/items', [
        'name' => '大量資料測試',
        'description' => str_repeat('x', 2000), // 故意超過 1024 bytes
    ]);
    echo $result;
} catch (Exception $e) {
    error_log($e->getMessage());
}
?>

何時需要保留 100-continue?

極少數情況:

  • 上傳超大檔案(GB 級),希望先確認伺服器接受再傳輸本體
  • 目標 API 明文要求使用 100-continue 進行流控

對於 99% 的 API 串接場景,**建議預設禁用**以避免相容性問題。

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