使用curl_multi_exec批量请求时HTTP状态码交替返回200与0的问题
解决curl_multi_exec批量请求状态码交替200和0的问题
我看到你用curl_multi_exec实现批量请求时遇到了状态码交替200和0的问题,这大概率是因为你的curl_multi事件循环逻辑有问题,没有正确等待请求完成就提前结束了处理。
问题根源
你当前的执行循环是:
do { curl_multi_exec($mh, $stillRunning); } while ($stillRunning);
这种空循环会导致CPU占用极高,而且curl_multi_exec在非阻塞模式下,不会等待请求完成就返回,直接循环的话可能会让部分请求还没建立连接或完成响应就被后续的curl_multi_remove_handle和curl_close中断,从而返回状态码0。
修复方案
需要在循环中加入curl_multi_select来等待活动连接,让curl有时间处理请求的响应,确保所有请求都能正确完成。同时,还要处理curl_multi_exec返回的错误状态,避免无限循环。
修正后的完整代码片段如下:
try{ $allproducts = json_decode(self::getProductbyEan()); $requests = array(); $mh = curl_multi_init(); foreach($allproducts as $k => $url){ $url = 'https://nartastaging.retailpath.com.au/cgi-bin/WebObjects/NARTAStaging.woa/ra/Product/'.$url->id.'.json'; $requests[$k] = array(); $requests[$k]['url'] = $url; $requests[$k]['curl_handle'] = curl_init($url); curl_setopt($requests[$k]['curl_handle'], CURLOPT_RETURNTRANSFER, true); curl_setopt($requests[$k]['curl_handle'], CURLOPT_FOLLOWLOCATION, true); curl_setopt($requests[$k]['curl_handle'], CURLOPT_TIMEOUT, 10); curl_setopt($requests[$k]['curl_handle'], CURLOPT_CONNECTTIMEOUT, 10); curl_setopt($requests[$k]['curl_handle'], CURLOPT_SSL_VERIFYHOST, false); curl_setopt($requests[$k]['curl_handle'], CURLOPT_SSL_VERIFYPEER, false); curl_setopt($requests[$k]['curl_handle'], CURLOPT_HTTPAUTH, CURLAUTH_BASIC); curl_setopt($requests[$k]['curl_handle'], CURLOPT_USERPWD, "$login:$password"); curl_multi_add_handle($mh, $requests[$k]['curl_handle']); } $stillRunning = false; curl_multi_setopt($mh, CURLMOPT_MAXCONNECTS, 5); // 修正后的事件循环 do { $execStatus = curl_multi_exec($mh, $stillRunning); // 如果执行出错,跳出循环 if ($execStatus != CURLM_OK) { break; } // 等待活动连接,超时1秒 $selectStatus = curl_multi_select($mh, 1); // 如果select返回-1,兼容旧版本curl,短暂休眠避免空循环 if ($selectStatus == -1) { usleep(100); } } while ($stillRunning || $execStatus == CURLM_CALL_MULTI_PERFORM); foreach($requests as $k => $request){ $requests[$k]['http_code'] = curl_getinfo($request['curl_handle'], CURLINFO_HTTP_CODE); // 可以顺便获取curl错误信息,排查问题 $requests[$k]['curl_error'] = curl_error($request['curl_handle']); $requests[$k]['curl_errno'] = curl_errno($request['curl_handle']); curl_multi_remove_handle($mh, $request['curl_handle']); curl_close($requests[$k]['curl_handle']); } curl_multi_close($mh); print_r($requests); }catch(Exception $e){ wp_die($e->getMessage()); }
关键改进点
- 加入
curl_multi_select($mh, 1):让程序等待1秒,直到有活动的curl连接需要处理,避免空循环浪费CPU,同时确保请求有足够时间完成。 - 处理
curl_multi_exec的返回值:如果执行出错(返回非CURLM_OK),直接跳出循环,避免无限循环。 - 兼容
curl_multi_select返回-1的情况:旧版本curl可能返回-1,此时用usleep(100)短暂休眠,防止空循环。 - 增加了curl错误信息的获取:方便你排查如果还有请求失败的具体原因(比如连接超时、认证错误等)。
另外,你可以检查一下那些原本返回0的请求对应的curl_error和curl_errno,如果还有问题,能更精准定位(比如是否是目标服务器的并发限制,或者认证信息是否正确)。
内容的提问来源于stack exchange,提问作者Elland
相关产品推荐
相关产品推荐

