PHP中如何基于一个API响应在foreach循环内调用另一个API?
基于curl_multi的API批量调用与数据入库实现模板
以下是适配你场景的PHP通用实现方案,解决串行调用API效率低、执行无法结束的问题,同时规范数据入库流程:
核心流程
- 调用第一个API获取目标ID数组
- 利用
curl_multi并发调用第二个API(每个ID对应一个请求) - 合并两个API的响应数据
- 批量插入MySQL数据库
完整代码实现
<?php // -------------------------- 配置区 -------------------------- // 第一个API地址(获取ID数组) $firstApiUrl = 'https://example.com/api/get-ids'; // 第二个API地址模板({id}为占位符) $secondApiTemplate = 'https://example.com/api/get-detail/{id}'; // MySQL数据库配置 $dbConfig = [ 'host' => 'localhost', 'dbname' => 'your_database', 'user' => 'your_user', 'password' => 'your_password' ]; // curl并发请求的批次大小(避免一次性创建过多请求导致资源耗尽) $batchSize = 10; // -------------------------- 第一步:获取ID数组 -------------------------- $ch = curl_init($firstApiUrl); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_TIMEOUT, 10); // 设置超时防止无限等待 $idResponse = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); // 处理第一个API的响应 if ($httpCode !== 200 || empty($idResponse)) { die('Failed to fetch ID array from first API'); } $idArray = json_decode($idResponse, true); // 校验ID数组格式(根据实际API返回结构调整) if (!is_array($idArray) || empty($idArray)) { die('Invalid ID array format'); } // -------------------------- 第二步:curl_multi批量调用第二个API -------------------------- $detailData = []; // 分批处理ID,避免并发数过大 $idBatches = array_chunk($idArray, $batchSize); foreach ($idBatches as $batch) { $mh = curl_multi_init(); $curlHandles = []; // 为每个ID创建curl handle并加入multi批处理 foreach ($batch as $id) { $apiUrl = str_replace('{id}', $id, $secondApiTemplate); $ch = curl_init($apiUrl); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_TIMEOUT, 8); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); $curlHandles[$id] = $ch; curl_multi_add_handle($mh, $ch); } // 执行批量请求 $running = null; do { curl_multi_exec($mh, $running); curl_multi_select($mh); // 等待请求完成,减少CPU占用 } while ($running > 0); // 收集每个请求的响应 foreach ($curlHandles as $id => $ch) { $response = curl_multi_getcontent($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); if ($httpCode === 200 && !empty($response)) { $detail = json_decode($response, true); // 合并ID与详情数据(根据实际需求调整字段) $detailData[] = [ 'source_id' => $id, 'detail_data' => json_encode($detail), // 若需存储结构化数据,可存JSON // 可额外添加第一个API的关联字段(如果有) ]; } else { // 记录错误日志(生产环境建议写入日志文件) error_log("Failed to fetch detail for ID {$id}, HTTP code: {$httpCode}"); } // 释放单个curl handle curl_multi_remove_handle($mh, $ch); curl_close($ch); } // 释放multi handle curl_multi_close($mh); } // -------------------------- 第三步:批量插入MySQL -------------------------- if (empty($detailData)) { die('No valid data to insert'); } try { $pdo = new PDO( "mysql:host={$dbConfig['host']};dbname={$dbConfig['dbname']};charset=utf8mb4", $dbConfig['user'], $dbConfig['password'], [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC ] ); // 预处理插入语句(根据你的表结构调整字段) $insertSql = "INSERT INTO your_table (source_id, detail_data, created_at) VALUES (?, ?, NOW())"; $stmt = $pdo->prepare($insertSql); // 开启事务提升插入效率 $pdo->beginTransaction(); foreach ($detailData as $data) { $stmt->execute([ $data['source_id'], $data['detail_data'] ]); } $pdo->commit(); echo 'Data inserted successfully. Total rows: ' . count($detailData); } catch (PDOException $e) { $pdo->rollBack(); die('Database error: ' . $e->getMessage()); } ?>
关键说明
- curl_multi优势:替代串行foreach的curl调用,通过并发请求大幅减少总耗时,同时避免单个请求阻塞导致程序无法结束
- 批次处理:设置
$batchSize控制并发数,防止一次性创建过多curl连接耗尽服务器资源 - 超时控制:为每个curl请求设置
CURLOPT_TIMEOUT,避免请求挂起导致程序僵死 - 数据库安全:使用PDO预处理语句防止SQL注入,开启事务保证数据一致性
- 错误处理:针对API请求失败、数据库异常做了基础捕获,生产环境建议扩展日志记录逻辑
内容的提问来源于stack exchange,提问作者Cristian Garib
相关产品推荐
相关产品推荐

