微信支付回調、統一下單等接口調用 api.mch.weixin.qq.com 時,若服務器啟用 IPv6,DNS 解析極慢(甚至超時),導致支付流程卡頓。本文深度分析根因,提供 cURL 強制 IPv4、系統級禁用 IPv6 等多層級解決方案。
# wget 測試 wget api.mch.weixin.qq.com # Resolving api.mch.weixin.qq.com... (長時間無響應) # 強制 IPv4 即秒開 wget -4 api.mch.weixin.qq.com # Resolving api.mch.weixin.qq.com... 123.151.71.149, 123.151.79.109 # Connecting... connected.
getaddrinfo() 默認 AF_UNSPEC,優先查詢 AAAA (IPv6) 再查 A (IPv4)api.mch.weixin.qq.com 無 AAAA 記錄minorshort.weixin.qq.com,後者有 IPv6 CNAME 但無實際 AAAA 解析qq.com 主域有完善 IPv6 部署,解析極快#include#include #include int main() { struct addrinfo hints = {}, *res; hints.ai_family = AF_INET6; // 強制 IPv6 hints.ai_socktype = SOCK_STREAM; int err = getaddrinfo("api.mch.weixin.qq.com", NULL, &hints, &res); if (err) { std::cerr << "getaddrinfo: " << gai_strerror(err) << std::endl; return 1; } std::cout << "Success with IPv6\n"; for (auto p = res; p; p = p->ai_next) { char ip[INET6_ADDRSTRLEN]; inet_ntop(AF_INET6, &((struct sockaddr_in6*)p->ai_addr)->sin6_addr, ip, sizeof(ip)); std::cout << ip << std::endl; } freeaddrinfo(res); return 0; }
編譯運行:g++ test.cpp -o test && ./test 將長時間無輸出,確認 IPv6 解析卡死。
$ch = curl_init(); curl_setopt($ch, CURLOPT_URL, 'https://api.mch.weixin.qq.com/...'); curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); // 關鍵行 // 其他選項... $result = curl_exec($ch);
PHP cURL 7.10.8+ 支持 CURLOPT_IPRESOLVE,常量:CURL_IPRESOLVE_V4、CURL_IPRESOLVE_V6、CURL_IPRESOLVE_WHATEVER(默認)。
$ctx = stream_context_create([
'http' => [
'bindto' => '0.0.0.0:0', // 綁定 IPv4 任意地址
],
'ssl' => [
'verify_peer' => false,
]
]);
$result = file_get_contents($url, false, $ctx);
# 臨時 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 生效
123.151.71.149 api.mch.weixin.qq.com 123.151.79.109 api.mch.weixin.qq.com
風險:微信更換機房 IP 變更將導致服務中斷,需監控並自動更新。
# /etc/resolv.conf 或 /etc/systemd/resolved.conf # 禁用 IPv6 查詢 ResolveUnicastSingleLabel=no # 或使用只返回 A 記錄的 DNS(如 114.114.114.114)
| 語言/框架 | 強制 IPv4 方式 |
|---|---|
| Java | System.setProperty("java.net.preferIPv4Stack", "true") |
| Go | Dialer{Control: func(_, addr string) { return &net.TCPAddr{IP: net.ParseIP("0.0.0.0")} }} |
| Python requests | requests.get(url, hooks={'response': lambda r: r.connection.sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 0)}) 或 HTTPAdapter 綁定 IPv4 |
| Node.js | http.request({family: 4, ...}) 或 dns.setDefaultResultOrder('ipv4first') (Node 17+) |
| Nginx upstream | resolver 114.114.114.114 ipv6=off; |
api.mch.weixin.qq.com 提供有效 AAAA 記錄,或移除 CNAME 鏈中的 IPv6 別名在微信修復前,在所有支付相關 cURL 請求中添加 CURLOPT_IPRESOLVE => CURL_IPRESOLVE_V4 是成本最低、風險最小、效果最立竿見影的方案。