Skip to content

分页、范围读取与文件接口 ​

公开客户端常见的数据形态有“完整对象”“数组列表”“范围分页”和“二进制文件”。本页给出不会把空数据、重复数据或文件错误解析混在一起的实现方式。

范围参数 ​

游玩记录接口使用 start 和 end:

json
{
  "token": "<TOKEN>",
  "start": 0,
  "end": 50
}

文档约定范围为 [start, end):包含 start,不包含 end。请求 0–50 最多得到 50 条,不应把 end 当作最后一个包含位置。

正确推进游标 ​

不要只用固定步长推进,因为服务可能返回少于请求数量的条目:

js
let start = 0;
const pageSize = 50;
const all = [];

while (true) {
  const page = await getPlaylog({ start, end: start + pageSize });
  const rows = Array.isArray(page.playlogList) ? page.playlogList : [];
  all.push(...rows);

  if (rows.length === 0 || rows.length < pageSize) break;
  start += rows.length;
}

如果响应提供 total,还要同时判断 start + rows.length >= total。服务端数据在读取期间可能新增,不能假设总数永远不变。

防止重复和遗漏 ​

分页读取过程中:

  • 用服务返回的稳定记录标识去重(如果页面提供);
  • 不要用数组下标作为永久 ID;
  • 保留每页请求的起止范围和返回数量;
  • 请求失败时重试当前页,不要直接跳到下一页;
  • 发生 Token 失效时停止,不要从下一页继续请求;
  • UI 翻页和后台全量导出使用不同状态,避免互相覆盖。

页面只显示当前页是正常行为。用户点击“最后一页”时,客户端可以根据 total 计算范围;如果服务没有可靠总数,使用“下一页”直到返回空数组更安全。

空页和最后一页 ​

下面三种情况都可能得到空数组:

  1. 账号确实没有记录;
  2. 范围超出当前数据;
  3. 服务返回了过滤后的空页。

UI 应同时显示当前范围和账号上下文,避免把空页提示成“账号已清空”。

乐曲数据的嵌套列表 ​

用户乐曲数据可能位于:

text
data
└── userMusicList[]
    └── userMusicDetailList[]

客户端应把缺失的中间数组视为“当前没有可显示的记录”,而不是抛出异常。保留未知数字字段,避免未来版本增加字段时丢失信息。

成绩数字的显示要按字段语义处理:达成率可能是放大整数,状态值可能是枚举索引,DX 分数和游玩次数是不同单位。不要把网页已经格式化的百分比再次乘以 100。

列表接口的快照语义 ​

相片列表和上传缓存列表返回的是索引快照。下载或删除时必须使用本次列表返回的名称:

  1. 读取列表;
  2. 让用户选择一项;
  3. 记录选择时的列表版本/时间;
  4. 调用单项接口;
  5. 超时后重新读取列表。

不要在客户端根据文件名模式自行拼接未出现在列表中的索引。服务端可能有大小写、编码或保留字符规则。

图片与二进制文件 ​

文件接口可能返回:

  • 图片二进制;
  • 其它文件二进制;
  • JSON 成功/失败对象;
  • 空响应或错误页。

读取流程:

text
请求 → 检查 HTTP 状态 → 检查 Content-Type
   ├─ JSON:解析 success/msg
   ├─ 图片:按 Blob 预览或下载
   ├─ 其它文件:按下载流程保存
   └─ 未知:保留状态码并停止自动处理

图片预览器要限制最大内存和并发数量,关闭预览时释放对象 URL。浏览器本地缩略图缓存不是服务端备份,清除缓存不会删除服务端文件。

下载文件的安全处理 ​

  • 文件名只使用服务返回或用户确认的名称;
  • 下载路径由浏览器或受保护的应用目录决定;
  • 不根据扩展名直接执行文件;
  • 显示下载前确认账号和对象名称;
  • 记录文件大小和下载时间,不记录文件原文;
  • 分享前检查是否包含账号、二维码、个人信息或未公开内容。

上传和恢复对象 ​

上传缓存、普通备份和恢复对象可能随版本增加字段。客户端应:

  1. 保存完整 JSON;
  2. 显示已识别的摘要;
  3. 保留未知字段;
  4. 在恢复前显示来源、时间和账号提示;
  5. 在写入前要求确认;
  6. 写入后重新读取,而不是只相信返回条数。

不要把 data 中的对象重新序列化成只包含当前页面字段的“精简版本”,否则可能丢失未来字段。

交互式页面的分页体验 ​

页面应明确区分:

  • 首次加载;
  • 换页加载;
  • 下拉加载更多;
  • 正在刷新当前页;
  • 空数据;
  • 加载失败。

换页时保留上一页内容比直接显示空白更容易理解,但要显示加载提示并禁用重复翻页。用户离开页面时取消未完成请求,避免回调覆盖新账号的数据。

大数据量导出建议 ​

全量导出应:

  1. 先估算总量和磁盘空间;
  2. 分页读取并周期性保存检查点;
  3. 每页验证结构;
  4. 记录成功页数和最后范围;
  5. 失败后从最后一个未确认页继续;
  6. 完成后去重并校验条数;
  7. 将导出文件放在加密或受保护的位置。

导出中不要并行请求过多页,也不要把所有记录一次性放入浏览器内存。含个人信息的记录只用于授权目的,完成后按保留策略处理。

Released under the CC BY-NC-SA 4.0 License.