几种常见的API接口分页方案
1 概述
列表是互联网产品中很常见的一种内容排列形式,而且列表的数据集往往成千上万,一次性返回全量数据集的场景几乎不存在,所以出现了数据分页的需求。本文将总结常见的列表样式以及接口分页设计相关问题。
2 分页方案
常见的列表样式有卡片流、瀑布流、信息流等,我们可以总结为两种分页方式:
- 传统分页:通过显示的页码查询指定页的数据,多用于 PC 端数据变化不频繁的列表展示。
- 流式分页:通过滚动方式隐式加载更多的数据,适用 PC 和移动端大多场景。
2.1 基于偏移量
基于偏移是最常见的分页接口设计,其原理是通过页号和页大小指定某一分页的数据。例如:
// 请求
{
"page": 2,
"count": 10
}
// 响应
{
"data": [],
"total": 100
}
具体到数据库可以通过 offset + limit 实现:
select xxx from xxx where xxx order by xxx limit $count offset ($page-1)*$count;
或使用内存分页:
list = list.stream()
.skip((page-1)*count)
.limit(count)
.collect(Collecters.toList());
这种方案比较适合传统显示分页场景,有点是实现起来简单,支持分页跳转,支持向前、后翻页。
缺点也比较明显,主要来自两方面:
- 慢查询:通过数据库
limit
和offset
实现的分页性能较差,偏移量越大越明显。 - 动态数据:偏移量方案对数据变动支持也差,数据的插入或删除可能会导致数据重复或跳过,比如用户在查看第 10 页内容,此时第 1 页一条数据被删除,此时整个列表会往迁移,这会导致第 11 页跳过了 1 条数据。
2.2 基于游标
基于游标(cursor)的分页设计适用于动态数据场景,其原理是根据已获取的最后一条数据的 ID 作为参数来请求下一页数据。例如:
// 请求
{
"cursor": "2",
"count": 10
}
// 响应
{
"data": [],
"nextCursor": "3",
}
实现游标有很多方法,对于有自增主键 ID 的数据库表来说,按 ID 排序分页的实现比较简单,可以直接使用主键 ID 做 cursor:
select xxx from xxx where xxx and id>=$cursor limit $count+1;
这里有一个小技巧,可以每次分页查询都多查询一个元素作为 nextCursor 使用,同时可以用来判断是否有剩余数据。
游标分页方案优点就是性能好,对数据变动也有较好支持,不会因为数据的插入或删除导致数据重复或跳过。缺点是不能像偏移量方案可以任意跳转指定页,往前翻页也需要特别处理。
3 重复数据处理
3.1 基于时间
比如我们的微信朋友圈或者微博关注列表,是基于一个维度固定排序的。此类场景中数据只会从最后新增或删除,因此只需要维护好每个用户或 Session 维度的缓存即可。
由其朋友圈关系类数据,由于用户朋友关系数量的限制,完全可以在用户发布动态时以写扩散的方式讲数据分别写入对应朋友的朋友圈数据列表。为了提高该列表的性能,此列表除了使用 MySQL 等数据库持久化外,还可以使用 Redis 的 Zset 数据结构进行高效的缓存。
3.2 基于热度
在基于排序规则定期排序的数据列表场景,如微博热榜中,数据在列表中的位置会不断发生变化,这会导致用户在请求第二页时可能刷到重新排序后的第一页中的数据。
解决该问题很简单,数据的不断变化导致数据分页的复杂,那我们将数据分割成固定不变的数据处理即可使问题简单化:利用场景中定时更新的机制,维护多个版本的数据,用户第一次(或第一页)请求和一个数据版本绑定,这样就保证了数据的不重复。
这里的版本数量可以根据更新时间和用户停留时间估算,还可以采用一致性 Hash 的设计。
当然,如果列表数据集较少,完全还可以获取一次数据客户端进行分页。
3.3 基于推荐
在推荐列表场景中,数据列表并固定的排序规则,并且支持无限拉取,如抖音视频推荐列表。此列数据主要来源推荐系统定向召回和排序后数据,没有明确的分页界限,所以只需要对应的数据量即可,常见方法是在服务端基于用户投递历史以及客户端本地全量缓存进行去重过滤。
由于接口需要实时计算,请求耗时较长,往往会进行预请求,比如在列表倒数第几位开始拉取下一刷的数据。
相关文章
- API接口DTO测试数据构造的一个方式
- 看完这个接口测试面试题及参考答案,offer拿到手软
- 「接口自动化」软件测试涨薪核心技能、让薪资涨幅200%
- 百度语音接口api调用
- 在Winform混合式框架中整合外部API接口的调用
- api 和 C# 里的接口的区别?
- 接口测试框架实战(六) | 配置的数据驱动
- API接口管理工具postman等
- axios实战学习——调用城市天气api接口数据实现天气查询案例
- 【CBC加密链+多重哈希模块】在DE2-115开发板上实现基于CBC加密链的数据读写接口,其中用户口令转换为mastkey多重哈希模块
- CY7C68013与FPGA接口的Verilog
- API 接口应该如何设计?如何保证安全?如何签名?如何防重?
- 2022最全知识点——RF接口自动化框架项目实战
- Jmeter接口测试流程详解(中科软测认证中心)
- API 低代码开发:接口大师,一套开发、管理和提供接口的产品框架
- PHP 开发API接口签名验证
- 《Windows网络与通信程序设计(第3版)》——第2章 Winsock编程接口2.1 Winsock库
- 「基于Django的全民健康智慧中医数字服务平台」前端应用API接口功能(四)
- android开发支付宝接口开发流程(密钥篇)
- 面向对象的本质是算法的上下文封装,是同一类属的行为接口的一致性
- Jmeter接口测试-完成任务API
- Java 调用Restful API接口的几种方式--HTTPS
- SVNKit学习——使用低级别的API(ISVNEditor接口)直接操作Repository的目录和文件(五)
- centos7安装hadoop,配置eclipse和hdfs文件系统接口-运行案例测试
- 手机号码归属地查询免费api接口代码
- Django:前后端分离 djangorestframework开发API接口 serializer序列化认证组件
- sonar:api/ce/submit接口上传失败
- iOS - 利用 iTunes 接口检查 App 版本更新
- 【arduino学习】:Arduino编译ESP8266的任务(温湿度测量、超声波距离测量、声音检测模块、api接口调试、读取解析Json数据)
- API接口平台,包含各种各样的资源接口,方便开发和测试
- Java HttpClient 如何使用代理IP请求接口