
本文介绍在 api 仅支持固定页大小(如每页 100 条)且不返回总记录数或总页数时,如何使用 php + curl 迭代请求所有页面,准确汇总全部数据。
本文介绍在 api 仅支持固定页大小(如每页 100 条)且不返回总记录数或总页数时,如何使用 php + curl 迭代请求所有页面,准确汇总全部数据。
当调用分页型 REST API(如 https://api.shop.com/v1/products?page_size=100&page_number=N)时,若 API 不提供 total_count、last_page 或 has_more 等元信息,无法预知总页数——此时不能依赖猜测页码范围(例如 page_number=1..1000),而应采用“按需拉取、边界检测”的稳健策略:持续递增页码,直到某次响应数据量小于请求的 page_size,即判定为最后一页。
以下是完整、健壮的 PHP 实现示例(含错误处理与结果聚合):
<?php function fetchAllApiRecords($baseUrl, $pageSize = 100, $maxRetries = 3) {
$allRecords = [];
$pageNumber = 1;
$totalFound = 0;
do {
$url = sprintf('%s?page_size=%d&page_number=%d', $baseUrl, $pageSize, $pageNumber);
$attempts = 0;
$response = null;
// 重试机制:应对临时网络或限流错误
while ($attempts < $maxRetries && $response === null) {
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTPHEADER => ['Accept: application/json'],
CURLOPT_USERAGENT => 'PHP-APIClient/1.0',
]);
$raw = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode === 200 && !empty($raw)) {
$response = json_decode($raw, true);
if (json_last_error() !== JSON_ERROR_NONE) {
throw new RuntimeException("Invalid JSON response on page {$pageNumber}");
}
} else {
$attempts++;
if ($attempts >= $maxRetries) {
throw new RuntimeException("Failed to fetch page {$pageNumber} after {$maxRetries} retries (HTTP {$httpCode})");
}
usleep(100000); // 100ms backoff
}
}
// 假设 API 返回结构为 { "data": [...], "meta": {...} } 或直接返回数组
$records = is_array($response) && isset($response['data'])
? $response['data']
: ($response ?: []);
$count = count($records);
$allRecords = array_merge($allRecords, $records);
$totalFound += $count;
// 关键终止条件:本页返回记录数 $allRecords,
'total_count' => $totalFound,
'pages_fetched' => $pageNumber,
];
}
// 使用示例
try {
$result = fetchAllApiRecords('https://api.shop.com/v1/products');
echo "共获取 {$result['total_count']} 条记录,来自 {$result['pages_fetched']} 页。\n";
// 后续可对 $result['records'] 进行处理(入库、导出等)
} catch (Exception $e) {
error_log("API fetch failed: " . $e->getMessage());
die($e->getMessage());
}
关键注意事项:
- ✅ 不要硬编码页码上限:page_number 不支持范围语法(如 1..100),必须逐页请求;
- ✅ 以实际响应数据量为终止依据:count($records)
- ⚠️ 务必添加超时与重试:生产环境需防范网络抖动、服务端限流导致的偶发失败;
- ⚠️ 检查 API 响应结构:不同接口可能将数据置于 data、items 或根数组中,需适配解析逻辑;
- ? 避免无限循环风险:建议增加最大页数限制(如 if ($pageNumber > 1000) break;)作为兜底保护。
该方案无需预先知晓总量,兼容任意分页 API,是处理“无总数提示”分页场景的标准实践。
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!











