Echo Server:分页与列表接口优化

第五阶段:把固定 LIMIT 改成 page/page_size,为压测与高并发优化做准备

分页API 设计列表优化

0. 为什么分页必须放在压测前

性能优化文档中的压测脚本已经请求 page 和 page_size 参数,因此要先统一分页接口,否则压测对象不稳定。

项目说明
建议位置精选作品详情页 / 项目文档页
统一风格左侧导航、右侧正文、表格说明、折叠代码块、阶段总结。
阅读顺序建议从总览页进入,再按卡片顺序阅读。

1. 分页规则

所有列表接口都使用 page 和 page_size,后端限制 page_size 最大值,避免一次拉取过多数据。

page 默认值:1
page_size 默认值:20
page_size 最大值:100
非法 page 或 page_size:回退默认值
OFFSET 计算公式:(page - 1) * page_size

推荐接口:
GET /api/posts/latest?page=1&page_size=20
GET /api/posts/user?user_id=1&page=1&page_size=20
GET /api/users/home?user_id=1&page=1&page_size=10

2. 参数解析函数

对非法、空值、负数、过大 page_size 做兜底处理。

int parsePositiveInt(const std::string& value, int defaultValue, int maxValue) {
    try {
        int n = std::stoi(value);
        if (n <= 0) return defaultValue;
        if (n > maxValue) return maxValue;
        return n;
    } catch (...) {
        return defaultValue;
    }
}

int page = parsePositiveInt(req->getParameter("page"), 1, 100000);
int pageSize = parsePositiveInt(req->getParameter("page_size"), 20, 100);
int offset = (page - 1) * pageSize;

3. SQL 改造示例

使用 LIMIT ? OFFSET ? 占位符,不拼接 SQL 字符串。

SELECT p.id, p.user_id, u.username, p.content, p.image_url, p.created_at
FROM posts p
JOIN users u ON u.id = p.user_id
ORDER BY p.id DESC
LIMIT ? OFFSET ?;

// 参数顺序:
// 1. pageSize
// 2. offset

4. 验收命令

验证第一页、第二页、过大 page_size 和非法参数都能稳定返回。

curl -s "http://127.0.0.1:8080/api/posts/latest?page=1&page_size=20" | jq
curl -s "http://127.0.0.1:8080/api/posts/latest?page=2&page_size=20" | jq
curl -s "http://127.0.0.1:8080/api/posts/latest?page=-1&page_size=9999" | jq
curl -s "http://127.0.0.1:8080/api/posts/user?user_id=1&page=1&page_size=10" | jq