伺服器啟用 IPv6 後,PHP cURL 請求外部 API 偶發連線超時。根因:cURL 嘗試 IPv6 解析並連線,但目標主機 IPv6 不通或路由異常。解決方法:指定 cURL 僅使用 IPv4 解析與連線。
<?php
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
// 關鍵:強制 IPv4 解析(需 PHP 5.3+、cURL 7.10.8+)
if (defined('CURLOPT_IPRESOLVE') && defined('CURL_IPRESOLVE_V4')) {
curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
}
// 超時設定(建議總超時 = 連線超時 × 3)
$timeout = 10;
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout); // 連線階段超時
curl_setopt($ch, CURLOPT_TIMEOUT, $timeout * 3); // 總執行超時
$content = curl_exec($ch);
if ($content === false) {
$error = curl_error($ch);
$errno = curl_errno($ch);
// 記錄錯誤、告警、降級處理...
}
curl_close($ch);
?>
| 常數 | 值 | 含義 |
|---|---|---|
CURL_IPRESOLVE_V4 |
1 | 僅解析 IPv4 位址 (A 記錄) |
CURL_IPRESOLVE_V6 |
2 | 僅解析 IPv6 位址 (AAAA 記錄) |
CURL_IPRESOLVE_WHATEVER |
0 | 預設:嘗試所有位址族(cURL 決定順序) |
php -i | grep "cURL Version"、php -r "var_dump(defined('CURLOPT_IPRESOLVE'));"/etc/gai.conf 設定 IPv4 優先(precedence ::ffff:0:0/96 100),影響 getaddrinfo() 排序,所有語言受益。CURLE_COULDNT_CONNECT (7)、CURLE_OPERATION_TIMEDOUT (28) 錯誤率,異常時自動切換備用 IP/節點。<?php
$testUrls = ['https://ipv4.google.com', 'https://ipv6.google.com'];
foreach ($testUrls as $url) {
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
// 不設定 IPRESOLVE,觀察預設行為
$start = microtime(true);
$content = curl_exec($ch);
$time = microtime(true) - $start;
$info = curl_getinfo($ch);
echo "$url: HTTP {$info['http_code']}, Time: ${time}s, IP: {$info['primary_ip']}\n";
curl_close($ch);
}
?>
強制 IPv4 解析是 IPv6 過渡期最低成本、見效最快的相容性修復,配合系統層優化可徹底根治。