PHP curl_multi_exec批量请求随机跳过结果的异常排查
问题描述
使用curl_multi_exec()批量请求API,所有请求无报错且结果均存在,但在基于原$items数组遍历返回结果$res时,会随机跳过部分条目;但第三次遍历所有条目又能正常读取。相关代码如下:
function curl_multi ( array $apiUrls ) { $multiHandles = []; $results = []; // Initialize multi-handle $multiHandle = curl_multi_init(); foreach ($apiUrls as $item => $url) { $ch = curl_init($url); // Set cURL options curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); //curl_setopt($ch, CURLOPT_TIMEOUT, 3); curl_setopt( $ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4 ); curl_setopt( $ch, CURLOPT_TCP_FASTOPEN, true); curl_setopt( $ch, CURLOPT_ENCODING, ''); // Add individual handle to the multi-handle curl_multi_add_handle($multiHandle, $ch); $multiHandles[$item] = $ch; } // Execute multi-handle requests do { $status = curl_multi_exec($multiHandle, $active); curl_multi_select($multiHandle); // Non-blocking wait } while ($status === CURLM_CALL_MULTI_PERFORM || $active); // Process responses and close handles foreach ($multiHandles as $item => $ch) { $response = curl_multi_getcontent($ch); if ($response === false) { apiErr( "error $item > $apiUrls[$item]", curl_error($ch) ); } else { $results[$item] = json_decode( $response, true ); } curl_multi_remove_handle($multiHandle, $ch); curl_close($ch); } // Close the multi-handle curl_multi_close($multiHandle); return $results; } foreach( $items as $item ) { $apiUrls[$item] = "https://..."; } $res = curl_multi ( $apiUrls ); foreach( $items as $item ) { // do something with each $res[$item] // some items are skipped, even if they exists! }
异常原因分析
核心问题出在**json_decode失败导致对应条目值为null**,结合你遍历循环的判断逻辑引发了“跳过”假象:
- 当部分API返回的响应不是合法JSON格式时,
json_decode($response, true)会返回null,此时$results[$item]被赋值为null,但数组的键$item是真实存在的。 - 如果第二个循环中的处理代码是类似
if ($res[$item]) { ... }的布尔判断,PHP会将null解析为false,导致该条目被逻辑上“跳过”;但实际上数组键并未丢失,所以第三次遍历(比如改用array_key_exists($item, $res)检查键是否存在,或直接访问键而不做布尔判断)时,就能正常读取到null值。 - 这种“随机跳过”的表现,本质是API返回的JSON合法性不稳定——部分请求的响应格式不符合JSON规范,导致
json_decode失败。
验证与修复建议
- 验证原因:在第二个循环中添加
var_dump($res[$item]),会发现被跳过的条目值均为null,同时可打印对应API的$response内容,确认是否为合法JSON。 - 修复方案:
- 增加
json_decode的错误检测,避免直接赋值null:else { $decoded = json_decode($response, true); if (json_last_error() !== JSON_ERROR_NONE) { apiErr("JSON decode error $item > $apiUrls[$item]", json_last_error_msg()); $results[$item] = $response; // 或设置自定义默认值 } else { $results[$item] = $decoded; } } - 修改遍历循环的判断逻辑,改用键存在性检查替代值的布尔判断:
foreach( $items as $item ) { if (array_key_exists($item, $res)) { // 处理$res[$item]的逻辑 } }
- 增加
内容的提问来源于stack exchange,提问作者ipel
相关产品推荐
相关产品推荐

