如何通过Curl单连接发多请求?45K用户名批量查询提速问询
如何用PHP Curl实现批量请求提速(单连接/多请求)
嘿,针对你45000条用户名的批量请求需求,原来的循环单请求方式确实会因为频繁建立/断开连接导致耗时爆炸。下面给你两种高效的解决方案,都是基于Curl的批量处理能力,能大幅减少请求时间:
方案一:使用Curl Multi(批量并行请求)
这是PHP里处理大量Curl请求的标准方案,它能同时发起多个请求(而非串行等待),虽然不是严格意义上的“单连接”,但能彻底避免串行等待的时间浪费,效率提升非常明显。而且因为45k数据量太大,一定要分批处理,不然内存会直接撑不住。
代码示例(分批处理版)
<?php $username = ['123', '456', '789', ...]; // 你的45k条用户名数组 $ua = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36'; $batchSize = 50; // 每批处理50个请求,可根据服务器性能调整 $totalUsers = count($username); $results = []; for ($batchStart = 0; $batchStart < $totalUsers; $batchStart += $batchSize) { $batchUsers = array_slice($username, $batchStart, $batchSize); $mh = curl_multi_init(); $handles = []; // 为每个用户创建Curl句柄并加入multi批处理 foreach ($batchUsers as $uname) { $url = 'http://abc.com.pk/hxc/get_user_details.php?uname=' . urlencode($uname); // 记得urlencode用户名! $ch = curl_init($url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_USERAGENT, $ua); curl_setopt($ch, CURLOPT_TIMEOUT, 10); // 设置超时,避免单个请求卡住 curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); // 处理跳转(如果需要) // 把用户名和句柄关联,方便后续匹配结果 $handles[(int)$ch] = $uname; curl_multi_add_handle($mh, $ch); } // 执行批量请求 $running = null; do { curl_multi_exec($mh, $running); curl_multi_select($mh); // 等待活动连接,避免CPU空转 } while ($running > 0); // 收集结果并清理句柄 foreach ($handles as $chId => $uname) { $results[$uname] = curl_multi_getcontent($chId); // 结果与用户名绑定 curl_multi_remove_handle($mh, $chId); curl_close($chId); } curl_multi_close($mh); } // 处理最终结果数组 var_dump($results); ?>
关键注意事项:
- 分批处理:45k请求不能一次性全部加入multi,否则会占用大量内存,甚至被目标服务器判定为攻击。建议每批50-200个,根据目标服务器的抗压能力调整。
- Urlencode用户名:如果用户名包含特殊字符(比如空格、&、=等),一定要用
urlencode()处理,避免请求参数错误。 - 超时设置:必须设置
CURLOPT_TIMEOUT和CURLOPT_CONNECTTIMEOUT,防止单个请求卡住导致整个批次停滞。
方案二:使用HTTP/2多路复用(真正的单连接多请求)
如果目标服务器http://abc.com.pk支持HTTP/2,那么可以利用HTTP/2的多路复用特性,在同一个TCP连接里同时发送多个请求,这比Curl Multi的多连接并行效率更高,还能减少TCP握手的开销。
代码示例(HTTP/2批量请求)
<?php $username = ['123', '456', '789', ...]; $ua = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36'; $batchSize = 100; // HTTP/2支持更大批次,因为是单连接 $totalUsers = count($username); $results = []; for ($batchStart = 0; $batchStart < $totalUsers; $batchStart += $batchSize) { $batchUsers = array_slice($username, $batchStart, $batchSize); $mh = curl_multi_init(); $handles = []; foreach ($batchUsers as $uname) { $url = 'http://abc.com.pk/hxc/get_user_details.php?uname=' . urlencode($uname); $ch = curl_init($url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_USERAGENT, $ua); curl_setopt($ch, CURLOPT_TIMEOUT, 10); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5); // 开启HTTP/2支持 curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // 若服务器证书有问题可临时关闭,生产环境不建议 $handles[(int)$ch] = $uname; curl_multi_add_handle($mh, $ch); } // 执行逻辑和Curl Multi一致 $running = null; do { curl_multi_exec($mh, $running); curl_multi_select($mh); } while ($running > 0); // 收集结果 foreach ($handles as $chId => $uname) { $results[$uname] = curl_multi_getcontent($chId); curl_multi_remove_handle($mh, $chId); curl_close($chId); } curl_multi_close($mh); } var_dump($results); ?>
验证服务器是否支持HTTP/2:
你可以在终端执行curl -I --http2 http://abc.com.pk命令测试,如果返回的响应头里有HTTP/2 200,说明支持HTTP/2。
额外优化建议
- 复用DNS缓存:设置
curl_setopt($ch, CURLOPT_DNS_CACHE_TIMEOUT, 3600);,避免重复解析域名。 - 禁用不必要选项:比如不需要返回头的话,设置
CURLOPT_HEADER, false,减少数据传输量。 - 错误处理:加入
curl_errno()和curl_error()的判断,处理请求失败的情况,甚至可以添加重试机制。 - 异步处理(可选):如果你的PHP环境支持,可以用Swoole等异步框架处理,效率会更高,但学习成本也相对高一些。
内容的提问来源于stack exchange,提问作者Talha Sarwar
相关产品推荐
相关产品推荐

