选项A:带时间戳的键集分页
为了避免您提到的偏移量分页的缺点,您可以使用基于键集的分页。通常,实体有一个时间戳,说明它们的创建或修改时间。此时间戳可用于分页:只需将最后一个元素的时间戳作为下一个请求的查询参数传递。服务器反过来使用时间戳作为筛选条件(例如WHERE modificationDate >= receivedTimestampParameter)
{
"elements": [
{"data": "data", "modificationDate": 1512757070}
{"data": "data", "modificationDate": 1512757071}
{"data": "data", "modificationDate": 1512757072}
],
"pagination": {
"lastModificationDate": 1512757072,
"nextPage": "https://domain.de/api/elements?modifiedSince=1512757072"
}
}
这样,你就不会漏掉任何元素。这种方法对于许多用例来说应该足够好了。但是,请记住以下几点:
当一个页面的所有元素都具有相同的时间戳时,您可能会陷入无休止的循环。
当具有相同时间戳的元素重叠在两个页面时,可以将多个元素多次交付给客户端。
您可以通过增加页面大小和使用精确到毫秒的时间戳来减少这些缺点。
选项B:带有延续令牌的扩展键集分页
要处理上面提到的常规键集分页的缺点,可以向时间戳添加偏移量,并使用所谓的“延续令牌”或“游标”。偏移量是该元素相对于具有相同时间戳的第一个元素的位置。通常,令牌具有类似Timestamp_Offset的格式。它在响应中传递给客户端,并可以提交回服务器以检索下一页。
{
"elements": [
{"data": "data", "modificationDate": 1512757070}
{"data": "data", "modificationDate": 1512757072}
{"data": "data", "modificationDate": 1512757072}
],
"pagination": {
"continuationToken": "1512757072_2",
"nextPage": "https://domain.de/api/elements?continuationToken=1512757072_2"
}
}
令牌“1512757072_2”指向页面的最后一个元素,并表示“客户端已经获得了时间戳为1512757072的第二个元素”。这样,服务器就知道该往哪里继续。
请注意,您必须处理元素在两个请求之间发生更改的情况。这通常是通过向令牌添加校验和来实现的。这个校验和是对具有此时间戳的所有元素的id进行计算的。因此,我们最终得到了这样的令牌格式:Timestamp_Offset_Checksum。
有关此方法的更多信息,请参阅博客文章“使用延续令牌的Web API分页”。这种方法的一个缺点是实现起来很棘手,因为有许多需要考虑的极端情况。这就是为什么像continuation-token这样的库可以很方便(如果您使用Java/ JVM语言)。免责声明:我是这篇文章的作者和图书馆的合著者。