curl_exec() 執行需等待 ~5 秒才回應wget 命令列卡在 Resolving domain... 階段ping domain 卻正常秒回系統啟用 IPv6,但目標域名無 AAAA 記錄(IPv6 地址),導致:
ping 可能僅查 A 記錄,或本地 /etc/hosts 有快取,故不受影響# 強制 IPv4 測試
wget -4 example.com # 瞬間完成
curl --ipv4 example.com # 瞬間完成
# 強制 IPv6 測試(應超時或失敗)
wget -6 example.com # 等待超時
curl --ipv6 example.com # 等待超時
# 查看 DNS 記錄
dig example.com AAAA # 無回應或 NXDOMAIN
dig example.com A # 有回應
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://api.example.com/data');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
// 關鍵:強制解析為 IPv4
curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
$response = curl_exec($ch);
curl_close($ch);
# 暫時停用(重啟失效)
sysctl -w net.ipv6.conf.all.disable_ipv6=1
sysctl -w net.ipv6.conf.default.disable_ipv6=1
# 永久停用 /etc/sysctl.conf
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
net.ipv6.conf.lo.disable_ipv6 = 1
# sysctl -p 生效
# /etc/hosts
192.168.1.100 api.example.com
option timeout:1 縮短超時class HttpClient {
private $defaultOptions = [
CURLOPT_TIMEOUT => 10,
CURLOPT_CONNECTTIMEOUT => 5,
CURLOPT_IPRESOLVE => CURL_IPRESOLVE_V4, // 預設強制 IPv4
CURLOPT_SSL_VERIFYPEER => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_MAXREDIRS => 5,
CURLOPT_USERAGENT => 'MyApp/1.0 (PHP/' . PHP_VERSION . ')',
];
public function get(string $url, array $options = []): string {
$ch = curl_init($url);
curl_setopt_array($ch, $this->defaultOptions + $options);
$response = curl_exec($ch);
if ($response === false) {
$error = curl_error($ch);
$errno = curl_errno($ch);
curl_close($ch);
throw new \RuntimeException("cURL 錯誤 [$errno]: $error");
}
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode >= 400) {
throw new \RuntimeException("HTTP $httpCode: $response");
}
return $response;
}
// 允許特定請求使用 IPv6
public function getIpv6(string $url): string {
return $this->get($url, [CURLOPT_IPRESOLVE => CURL_IPRESOLVE_V6]);
}
}
use GuzzleHttp\Client;
$client = new Client([
'curl' => [
CURLOPT_IPRESOLVE => CURL_IPRESOLVE_V4,
],
'timeout' => 10,
'connect_timeout' => 5,
]);
$response = $client->request('GET', 'https://api.example.com/data');
| 現象 | 可能原因 | 驗證命令 | 解決 |
|---|---|---|---|
| cURL/wget 慢、ping 快 | IPv6 AAAA 記錄缺失導致超時回退 | dig domain AAAA / wget -4 domain | CURLOPT_IPRESOLVE=V4 |
| 間歇性慢 | DNS 伺服器不穩/EDNS 問題 | dig @8.8.8.8 domain | 換 DNS/縮短 timeout |
| 特定域名慢 | 權威 DNS 無 IPv6 回應 | dig +trace domain | 聯繫域名方新增 AAAA |
| 容器內慢 | Docker 網路 IPv6 設定 | docker run --dns=8.8.8.8 | 指定 DNS/停用 IPv6 |
**「網路慢先查 DNS,DNS 慢先查 IPv6」** 是排查 cURL/wget 緩慢的黃金法則。現代 Linux 發行版預設啟用 IPv6,但許多內部/舊域名缺乏 AAAA 記錄,導致 5 秒預設超時成為隱形效能殺手。在 HTTP 客戶端預設強制 IPv4 (CURL_IPRESOLVE_V4) 是最低成本、最高相容的緩解方案,長期應推動基礎設施完善 IPv6 部署。