0

0

API分页数据循环获取教程

霞舞

霞舞

发布时间:2025-11-19 16:04:14

|

241人浏览过

|

来源于php中文网

原创

API分页数据循环获取教程

本文详细介绍了如何通过异步循环机制,从支持分页的api中高效、完整地获取所有数据。针对api每次请求返回结果数量受限的场景,教程演示了如何利用javascript的`async/await`和`fetch`,通过动态调整请求参数(如`start`或`page`),并结合api响应中的总数信息,迭代地请求并累积数据,直至所有可用结果被成功检索。

理解API分页与数据检索挑战

在与许多Web API交互时,一个常见的情况是API为了优化性能和管理资源,会限制单次请求返回的数据量。例如,一个搜索API可能每次只返回50条结果,即使总共有数百甚至数千条结果可用。为了获取所有数据,开发者需要执行一系列连续的请求,每次请求获取下一批结果,这个过程被称为“分页”。

挑战在于如何有效地管理这些连续请求:

  1. 如何确定需要执行多少次请求? 通常,API响应会包含一个总结果数。
  2. 如何构建每次请求的URL? 需要根据当前已获取的数据量或页码来调整请求参数,例如start(起始偏移量)或page(页码)。
  3. 如何累积所有请求的数据? 将每次请求返回的数据合并到一个集合中。
  4. 何时停止循环? 当所有可用数据都已获取时,循环应终止。

核心策略:异步循环与动态参数调整

解决上述挑战的关键在于使用一个异步循环结构,它能够:

  1. 逐次发送请求: 每次迭代发送一个API请求。
  2. 等待响应: 使用async/await确保前一个请求完成后再处理数据并发送下一个请求。
  3. 更新请求参数: 根据已获取的数据量或当前循环次数来计算下一个请求的start或page参数。
  4. 累积数据: 将每次请求返回的数据追加到总结果集中。
  5. 判断终止条件: 比较已累积的数据量与API报告的总数据量,决定是否继续循环。

实践示例:使用JavaScript实现API分页数据获取

以下是一个使用JavaScript实现通用API分页数据获取的示例,它模拟了从一个分页API(如Indeed搜索API)获取所有结果的过程。

/**
 * 异步函数,用于从支持分页的API获取所有数据。
 * 假设API的响应结构包含一个指示总结果数的字段(如 'totalResults')
 * 并且支持通过 'start' 和 'limit' 参数进行分页。
 *
 * @param {string} baseUrl API的基础URL,不包含分页参数。
 * @param {object} initialQueryParams 初始查询参数,不包含分页参数。
 * @param {number} limitPerPage 每次请求获取的最大结果数。
 * @param {string} totalResultsKey API响应中表示总结果数的键名。
 * @returns {Promise} 包含所有从API获取的数据的Promise。
 */
async function fetchAllPaginatedData(baseUrl, initialQueryParams, limitPerPage, totalResultsKey) {
    let allResults = []; // 用于累积所有结果的数组
    let currentOffset = 0; // 当前请求的起始偏移量
    let totalAvailable = Infinity; // 初始设定为无限大,等待API响应提供真实值

    // 转换为URLSearchParams对象,便于管理查询参数
    const params = new URLSearchParams(initialQueryParams);

    // 循环直到所有数据都被获取
    while (allResults.length < totalAvailable) {
        // 设置当前请求的分页参数
        params.set('start', currentOffset.toString());
        params.set('limit', limitPerPage.toString());

        const url = `${baseUrl}?${params.toString()}`;

        try {
            console.log(`Fetching data from: ${url}`);
            const response = await fetch(url);

            if (!response.ok) {
                throw new Error(`HTTP error! Status: ${response.status}`);
            }

            const responseJson = await response.json();

            // 假设API响应的数据字段是 'data',并且总数字段是动态传入的 'totalResultsKey'
            const currentBatch = responseJson.data || [];
            totalAvailable = responseJson[totalResultsKey] || 0; // 更新总可用结果数

            allResults = allResults.concat(currentBatch); // 累积当前批次的数据

            // 更新下一个请求的偏移量
            currentOffset += currentBatch.length;

            // 如果当前批次为空,且allResults.length < totalAvailable,
            // 说明可能API已无更多数据,或者API返回的总数不准确,应终止循环
            if (currentBatch.length === 0 && allResults.length < totalAvailable) {
                console.warn("API returned empty batch but total results suggest more data. Terminating loop to prevent infinite requests.");
                break;
            }

        } catch (error) {
            console.error(`Error fetching data: ${error.message}`);
            // 在实际应用中,这里可能需要更复杂的错误处理,如重试机制
            break; // 遇到错误时终止循环
        }
    }

    console.log(`Finished fetching. Total items collected: ${allResults.length}`);
    return allResults;
}

// 模拟Indeed API的调用
// 注意:以下URL和totalResultsKey是示例,实际Indeed API可能需要认证或其他特定参数
const indeedApiBaseUrl = "https://resumes.indeed.com/rpc/search";
const indeedInitialParams = {
    q: "sales",
    l: "Orlando,FL",
    lmd: "3day",
    radius: "25",
    indeedcsrftoken: "test_tokent" // 示例token
};
const indeedLimit = 50; // Indeed API每次请求的限制
const indeedTotalKey = "totalAvailableResults"; // 假设Indeed API返回的总数键名

// 调用函数并处理结果
(async () => {
    try {
        const allIndeedResults = await fetchAllPaginatedData(
            indeedApiBaseUrl,
            indeedInitialParams,
            indeedLimit,
            indeedTotalKey
        );
        console.log("All Indeed search results:", allIndeedResults);
        // 在这里可以进一步处理所有获取到的数据
    } catch (error) {
        console.error("Failed to fetch all Indeed results:", error);
    }
})();

// 另一个通用API的示例(如问题答案中使用的passenger API)
// 假设该API使用 'page' 和 'size',且总数键名为 'totalPassengers'
const passengerApiBaseUrl = "https://api.instantwebtools.net/v1/passenger";
const passengerInitialParams = {}; // 该API可能不需要初始查询参数
const passengerLimit = 100; // 每次请求的限制
const passengerTotalKey = "totalPassengers"; // API响应中总乘客数的键名

async function fetchAllPaginatedDataByPage(baseUrl, initialQueryParams, limitPerPage, totalResultsKey) {
    let allResults = [];
    let currentPage = 0; // 从第0页开始
    let totalAvailable = Infinity;

    const params = new URLSearchParams(initialQueryParams);

    while (allResults.length < totalAvailable) {
        params.set('page', currentPage.toString());
        params.set('size', limitPerPage.toString());

        const url = `${baseUrl}?${params.toString()}`;

        try {
            console.log(`Fetching data from: ${url}`);
            const response = await fetch(url);
            if (!response.ok) {
                throw new Error(`HTTP error! Status: ${response.status}`);
            }
            const responseJson = await response.json();

            const currentBatch = responseJson.data || [];
            totalAvailable = responseJson[totalResultsKey] || 0;

            allResults = allResults.concat(currentBatch);
            currentPage++; // 切换到下一页

            if (currentBatch.length === 0 && allResults.length < totalAvailable) {
                console.warn("API returned empty batch but total results suggest more data. Terminating loop.");
                break;
            }

        } catch (error) {
            console.error(`Error fetching data: ${error.message}`);
            break;
        }
    }
    console.log(`Finished fetching. Total items collected: ${allResults.length}`);
    return allResults;
}

(async () => {
    try {
        const allPassengers = await fetchAllPaginatedDataByPage(
            passengerApiBaseUrl,
            passengerInitialParams,
            passengerLimit,
            passengerTotalKey
        );
        console.log("All passengers:", allPassengers);
    } catch (error) {
        console.error("Failed to fetch all passengers:", error);
    }
})();

代码解析与注意事项

  1. fetchAllPaginatedData 函数:

    • 这是一个通用的异步函数,接受API的基础URL、初始查询参数、每页限制和表示总结果数的键名。
    • allResults 数组用于存储从所有请求中累积的数据。
    • currentOffset 变量跟踪当前请求的起始位置(对于使用start参数的API)。
    • totalAvailable 变量存储API报告的总结果数,用于判断循环终止条件。
    • URLSearchParams 用于方便地构建和管理URL查询参数。
  2. 循环条件 while (allResults.length

    • 这是循环的核心。只要已收集的结果数量小于API报告的总结果数,就继续请求。
    • 初始时 totalAvailable 设为 Infinity,确保至少会执行一次请求来获取真实的 totalAvailable 值。
  3. 请求参数设置:

    Ideogram
    Ideogram

    Ideogram是一个全新的文本转图像AI绘画生成平台,擅长于生成带有文本的图像,如LOGO上的字母、数字等。

    下载
    • 在每次循环中,params.set('start', currentOffset.toString()) 和 params.set('limit', limitPerPage.toString()) 更新了分页参数。
    • 对于使用page和size的API,需要相应地调整为params.set('page', currentPage.toString())和params.set('size', limitPerPage.toString()),并递增currentPage。
  4. fetch 和 async/await:

    • await fetch(url) 发送异步请求并等待响应。
    • await response.json() 解析JSON格式的响应体。
    • 使用 try...catch 块来捕获网络错误或API返回的非成功状态码,增强代码健壮性。
  5. 数据累积与偏移量更新:

    • allResults = allResults.concat(currentBatch) 将当前请求获取的数据追加到总结果集中。
    • currentOffset += currentBatch.length 更新偏移量,为下一次请求准备正确的start值。对于页码,则是currentPage++。
  6. 终止条件细化:

    • 除了 allResults.length
  7. 错误处理:

    • 示例中包含了基本的错误日志。在生产环境中,可能需要更复杂的错误处理机制,例如:
      • 重试逻辑: 对于瞬时网络错误或API服务不稳定,可以实现指数退避重试。
      • 用户通知: 向用户显示友好的错误消息。
      • 告警: 将错误记录到日志系统并触发告警。
  8. API特定性:

    • 不同的API可能使用不同的分页参数名称(如offset/limit、page/size、start/count等)。
    • API响应中表示总结果数的键名也可能不同(如total、total_count、meta.total等)。
    • 在实际应用中,你需要根据具体API文档调整这些参数和键名。

总结

通过异步循环结合动态参数调整和API响应中的总数信息,我们可以构建出健壮且高效的JavaScript代码来获取支持分页的API的所有数据。理解async/await、fetch以及如何根据API文档调整分页逻辑是实现这一功能的关键。务必考虑错误处理、API速率限制等因素,以确保应用程序的稳定性和可靠性。

相关专题

更多
js获取数组长度的方法
js获取数组长度的方法

在js中,可以利用array对象的length属性来获取数组长度,该属性可设置或返回数组中元素的数目,只需要使用“array.length”语句即可返回表示数组对象的元素个数的数值,也就是长度值。php中文网还提供JavaScript数组的相关下载、相关课程等内容,供大家免费下载使用。

552

2023.06.20

js刷新当前页面
js刷新当前页面

js刷新当前页面的方法:1、reload方法,该方法强迫浏览器刷新当前页面,语法为“location.reload([bForceGet]) ”;2、replace方法,该方法通过指定URL替换当前缓存在历史里(客户端)的项目,因此当使用replace方法之后,不能通过“前进”和“后退”来访问已经被替换的URL,语法为“location.replace(URL) ”。php中文网为大家带来了js刷新当前页面的相关知识、以及相关文章等内容

374

2023.07.04

js四舍五入
js四舍五入

js四舍五入的方法:1、tofixed方法,可把 Number 四舍五入为指定小数位数的数字;2、round() 方法,可把一个数字舍入为最接近的整数。php中文网为大家带来了js四舍五入的相关知识、以及相关文章等内容

730

2023.07.04

js删除节点的方法
js删除节点的方法

js删除节点的方法有:1、removeChild()方法,用于从父节点中移除指定的子节点,它需要两个参数,第一个参数是要删除的子节点,第二个参数是父节点;2、parentNode.removeChild()方法,可以直接通过父节点调用来删除子节点;3、remove()方法,可以直接删除节点,而无需指定父节点;4、innerHTML属性,用于删除节点的内容。

475

2023.09.01

JavaScript转义字符
JavaScript转义字符

JavaScript中的转义字符是反斜杠和引号,可以在字符串中表示特殊字符或改变字符的含义。本专题为大家提供转义字符相关的文章、下载、课程内容,供大家免费下载体验。

394

2023.09.04

js生成随机数的方法
js生成随机数的方法

js生成随机数的方法有:1、使用random函数生成0-1之间的随机数;2、使用random函数和特定范围来生成随机整数;3、使用random函数和round函数生成0-99之间的随机整数;4、使用random函数和其他函数生成更复杂的随机数;5、使用random函数和其他函数生成范围内的随机小数;6、使用random函数和其他函数生成范围内的随机整数或小数。

990

2023.09.04

如何启用JavaScript
如何启用JavaScript

JavaScript启用方法有内联脚本、内部脚本、外部脚本和异步加载。详细介绍:1、内联脚本是将JavaScript代码直接嵌入到HTML标签中;2、内部脚本是将JavaScript代码放置在HTML文件的`<script>`标签中;3、外部脚本是将JavaScript代码放置在一个独立的文件;4、外部脚本是将JavaScript代码放置在一个独立的文件。

656

2023.09.12

Js中Symbol类详解
Js中Symbol类详解

javascript中的Symbol数据类型是一种基本数据类型,用于表示独一无二的值。Symbol的特点:1、独一无二,每个Symbol值都是唯一的,不会与其他任何值相等;2、不可变性,Symbol值一旦创建,就不能修改或者重新赋值;3、隐藏性,Symbol值不会被隐式转换为其他类型;4、无法枚举,Symbol值作为对象的属性名时,默认是不可枚举的。

551

2023.09.20

c++主流开发框架汇总
c++主流开发框架汇总

本专题整合了c++开发框架推荐,阅读专题下面的文章了解更多详细内容。

80

2026.01.09

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
React 教程
React 教程

共58课时 | 3.5万人学习

TypeScript 教程
TypeScript 教程

共19课时 | 2.1万人学习

Bootstrap 5教程
Bootstrap 5教程

共46课时 | 2.9万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号