我需要从可分页的REST API的所有页面获取项目 . 我还需要开始处理项目,只要它们可用,不需要等待加载所有页面 . 为了做到这一点,我正在使用Spring WebFlux及其WebClient,并希望返回 Flux . 此外,我使用的REST API是速率限制的,每个响应都包含 Headers ,其中包含当前限制的详细信息:
当前窗口的大小
当前窗口中的剩余时间
在窗口中请求配额
请求在当前窗口中保留
对单个页面请求的响应如下所示:
{
"data": [],
"meta": {
"pagination": {
"total": 10,
"current": 1
}
}
}
数据数组包含实际项,而元对象包含分页信息 .
我当前的解决方案首先执行“虚拟”请求,只是为了获得总页数和速率限制 .
Mono paginated = client.get()
.uri(uri)
.exchange()
.flatMap(response -> {
HttpHeaders headers = response.headers().asHttpHeaders();
Limits limits = new Limits();
limits.setWindowSize(headers.getFirst("X-Window-Size"));
limits.setWindowRemaining(headers.getFirst("X-Window-Remaining"));
limits.setRequestsQuota(headers.getFirst("X-Requests-Quota");
limits.setRequestsLeft(headers.getFirst("X-Requests-Remaining");
return response.bodyToMono(Paginated.class)
.map(paginated -> {
paginated.setLimits(limits);
return paginated;
});
});
然后,我发出包含页码的Flux,并且对于每个页面,我都会执行REST API请求,每个请求都会延迟到足以使其超出限制,并返回提取项目的Flux:
return paginated.flatMapMany(paginated -> {
return Flux.range(1, paginated.getMeta().getPagination().getTotal())
.delayElements(Duration.ofMillis(paginated.getLimits().getWindowRemaining() / paginated.getLimits().getRequestsQuota()))
.flatMap(page -> {
return client.get()
.uri(pageUri)
.retrieve()
.bodyToMono(Item.class)
.flatMapMany(p -> Flux.fromIterable(p.getData()));
});
});
这确实有效,但我对此并不满意,因为:
它执行初始"dummy"请求以获取页数,然后重复相同的请求以获取实际数据 .
它仅在初始请求时获得速率限制,并且假设使用API的唯一限制赢得了 - 这可能不是真的,在这种情况下,它将获得超出限制的错误 .
所以我的问题是如何重构它以便它不需要初始请求(而是从第一个请求中获取限制,页码和数据,并继续通过所有页面,同时更新(并尊重)限制 .