You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何优雅实现支持分页的REST API消费?设计模式探讨

嘿,这个场景我之前做项目的时候刚好遇到过,来跟你唠唠可行的方案~

合适的设计模式

针对这种需要自动遍历分页结果的场景,有几个设计模式特别适配:

  • 迭代器模式:把分页获取数据的过程封装成一个迭代器,外部代码只需要遍历这个迭代器就能拿到所有数据,完全不用关心内部的分页逻辑(比如什么时候要传结果标识符、怎么检查剩余数量)。这种方式把数据获取和数据使用解耦,非常符合单一职责原则。
  • 模板方法模式:如果你们团队有多个类似的分页API,可以用这个模式做通用封装。把固定的流程(发起请求→解析结果→检查剩余→循环请求)做成模板,把每个API独有的部分(比如构造请求参数、解析响应格式)抽成可替换的回调或者抽象方法,这样后续新增API的时候只需要实现这些差异化部分就行,复用性拉满。
  • 生成器(Generator):虽然它不算严格意义上的经典设计模式,但在Python、JavaScript这类语言里用起来超级顺手。生成器可以一步步“产出”每一页的结果,既可以一次性把所有结果合并成列表,也可以惰性处理(比如边拿边处理,节省内存),代码简洁到爆炸。
递归VS更简洁的实现方式

递归确实能实现这个需求,但非常不推荐。原因很简单:如果分页数量特别多(比如几百上千页),递归会导致调用栈溢出,而且调试起来也比迭代麻烦得多。

更简洁可靠的方式是迭代式循环或者刚才说的生成器,核心逻辑就是:

  1. 发起初始请求,拿到第一页结果和分页标识
  2. 检查剩余数量,如果还有数据,就带着结果标识符发起下一轮请求
  3. 重复步骤2,直到剩余数量为0,把所有结果合并
示例代码

给你写两个简单的示例,方便你理解:

Python 同步版本(生成器实现)

def fetch_all_results(initial_query):
    # 发起初始请求,这里假设make_api_request是你封装的API调用函数
    response = make_api_request(initial_query)
    # 产出第一页的所有结果
    yield from response["items"]
    
    result_id = response["result_identifier"]
    remaining = response["remaining"]
    
    # 循环获取剩余数据
    while remaining > 0:
        next_response = make_api_request(None, result_id=result_id)
        yield from next_response["items"]
        
        # 更新剩余数量和结果标识符
        remaining = next_response["remaining"]
        result_id = next_response["result_identifier"]

# 调用时直接转成列表,就能拿到所有合并后的结果
all_results = list(fetch_all_results(your_initial_query_params))

JavaScript 异步版本(Async Generator)

// 封装的API请求函数,假设返回Promise
async function makeApiRequest(query, options = {}) {
    // 这里写你的API调用逻辑,比如fetch或者axios
}

async function* fetchAllResults(initialQuery) {
    let response = await makeApiRequest(initialQuery);
    // 产出第一页结果
    yield* response.items;
    
    let resultId = response.resultIdentifier;
    let remaining = response.remaining;
    
    while (remaining > 0) {
        response = await makeApiRequest(null, { resultId });
        yield* response.items;
        
        remaining = response.remaining;
        resultId = response.resultIdentifier;
    }
}

// 合并所有结果的函数
async function getAllResults(initialQuery) {
    const allItems = [];
    for await (const item of fetchAllResults(initialQuery)) {
        allItems.push(item);
    }
    return allItems;
}

这种实现方式不仅代码清晰,还能灵活应对不同场景:如果数据量特别大,不想一次性加载到内存里,直接遍历生成器处理单条数据就行;如果需要全量数据,转成列表也很方便。

内容的提问来源于stack exchange,提问作者webworm

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 09:52:50