after 参数参考
after (GraphQL) / $after (REST) 参数用于游标分页的翻页——传入上一页返回的游标令牌,获取下一页数据。与页码分页不同,游标分页在数据变动时不会重复或遗漏记录。
REST:$after
语法
?$after={cursor-token}cursor-token 是上一页响应中 nextLink 包含的游标值。客户端不需要解析其内容——它是不透明的 Base64 编码字符串。
示例
bash
# 第一页
curl "http://localhost:5000/api/Book?\$first=5"响应:
json
{
"value": [ ... ],
"nextLink": "http://localhost:5000/api/Book?$first=5&$after=eyJpZCI6NX0="
}从 nextLink 中提取 $after 值用于下一页:
bash
# 第二页
curl "http://localhost:5000/api/Book?\$first=5&\$after=eyJpZCI6NX0="遍历全量数据
javascript
async function fetchAllPages(baseUrl) {
let url = `${baseUrl}/api/Book?$first=20`;
const allItems = [];
while (url) {
const res = await fetch(url);
const data = await res.json();
allItems.push(...data.value);
url = data.nextLink || null;
}
return allItems;
}行为规则
| 规则 | 说明 |
|---|---|
必须与 $first 配合 | 单独传 $after 时使用默认分页大小 |
nextLink 可能不存在 | 不传 $first 且结果未超过默认大小时,无 nextLink |
| 游标不可跳页 | 只能跟随 nextLink 逐页访问,不能跳页 |
| 游标为不透明值 | 客户端不应解析或构造游标值 |
GraphQL:after
语法
graphql
{
books(first: {integer}, after: "{cursor}") {
items { ... }
hasNextPage
endCursor
}
}示例
graphql
# 第一页
{
books(first: 5) {
items { id title }
hasNextPage
endCursor
}
}响应:
json
{
"data": {
"books": {
"items": [ ... ],
"hasNextPage": true,
"endCursor": "eyJpZCI6NX0="
}
}
}取 endCursor 传给下一页的 after:
graphql
# 第二页
{
books(first: 5, after: "eyJpZCI6NX0=") {
items { id title }
hasNextPage
endCursor
}
}变量形式
graphql
query GetBooks($after: String) {
books(first: 20, after: $after) {
items { id title }
hasNextPage
endCursor
}
}遍历全量数据
javascript
async function fetchAllPages(gqlUrl) {
const allItems = [];
let cursor = null, hasNext = true;
while (hasNext) {
const res = await fetch(gqlUrl, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
query: `query($after: String) { books(first: 20, after: $after) { items { id title } hasNextPage endCursor } }`,
variables: { after: cursor }
})
});
const page = (await res.json()).data.books;
allItems.push(...page.items);
hasNext = page.hasNextPage;
cursor = page.endCursor;
}
return allItems;
}游标分页原理
游标分页通过记录"上一页最后一条记录的位置"来实现翻页。相比页码分页(page=1, page=2),游标分页的优势:
| 特性 | 游标分页 | 页码分页 |
|---|---|---|
| 数据变动时的一致性 | 不会重复或遗漏 | 可能重复或遗漏 |
| 跳页 | 不支持 | 支持 |
| 大偏移量性能 | 始终高效 | 偏移量大时性能下降 |
| 实现复杂度 | 低(跟随 nextLink/endCursor) | 低 |
数据墙DBW 选择游标分页是因为它在数据库层面表现更好(基于索引的游标比 OFFSET 更高效),且插入或删除中间数据时不会导致翻页结果错乱。
REST vs GraphQL 对照
| 操作 | REST | GraphQL |
|---|---|---|
| 翻页参数 | ?$after={token} | after: "{token}" |
| 获取下一页令牌 | 响应 nextLink 中包含 | 响应 endCursor 字段 |
| 检测是否有下一页 | nextLink 是否存在 | hasNextPage: true/false |
| 令牌格式 | Base64 编码 | Base64 编码 |
限定
| 限定 | 说明 |
|---|---|
| 不能跳页 | 只能跟随游标逐页访问 |
| 存储过程 | 不支持分页和 $after/after |
| 聚合查询 | 不支持分页 |
