分页参数需安全提取并校验:page至少为1,limit限制在10–100间,用strconv.atoi转换并检查error,失败返回400;offset必须由(page-1)*limit计算,不可信任前端传值。

分页参数怎么从 HTTP 请求里安全提取
直接用 c.Query("page") 和 c.Query("limit") 拿字符串再转整型,是最常见写法,但容易 panic 或返回默认值导致越界。必须做校验和兜底。
-
page至少为 1,小于 1 统一设为 1;limit建议限制在 10–100 之间,超出则截断(比如设为 50),防止恶意拉取全表 - 用
strconv.Atoi转换后要检查 error,失败时返回400 Bad Request并附带明确错误信息,比如"invalid page: must be integer" - 不要信任前端传来的
offset,永远用(page - 1) * limit计算,避免 offset 被篡改绕过页码逻辑
数据库查询怎么配合 Fiber 做分页拼接
Fiber 本身不处理数据库,关键在你怎么把分页参数喂给 ORM 或原生 SQL。以 PostgreSQL + pgx 为例,OFFSET / LIMIT 是最直白方式,但注意性能陷阱。
- 用
ORDER BY id(或有索引的字段)强制排序,否则分页结果可能错乱或重复 - 避免
OFFSET过大(比如OFFSET 100000),生产环境数据量大时会变慢;可考虑游标分页(WHERE id > ? ORDER BY id LIMIT ?)替代 - 示例片段:
rows, err := db.Query(ctx, "SELECT * FROM users WHERE status = $1 ORDER BY id DESC LIMIT $2 OFFSET $3", "active", limit, (page-1)*limit)
怎么把分页元数据塞进响应体
用户需要知道当前页、总条数、总页数、是否有下一页——这些不能靠前端猜,必须后端计算并返回。别只返回数据列表。
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
- 先查总数(
SELECT COUNT(*) FROM ...),再查分页数据;两个查询用同一份 WHERE 条件,避免不一致 - 总页数用
(total + limit - 1) / limit向上取整,别用math.Ceil(float64(total)/float64(limit)),整型更稳 - 推荐响应结构:
{"data": [...], "pagination": {"page": 2, "limit": 20, "total": 137, "pages": 7, "has_next": true, "has_prev": true}}
为什么分页接口要加 X-Total-Count 响应头
很多前端分页组件(比如 Element Plus 的 el-pagination)默认读这个 header 获取总数,比解析响应体更快、更解耦。
- 在返回 JSON 前加一行:
c.Response().Header.Set("X-Total-Count", strconv.FormatInt(int64(total), 10)) - 注意:如果用了 gzip 压缩,header 仍能被正确读取;但某些代理或 CDN 可能过滤自定义 header,上线前要验证
- 不建议同时在 body 和 header 里都放 total——容易不一致,优先信 header,body 里的
pagination.total只作兼容或调试用
实际分页最难的不是写几行 OFFSET,而是 WHERE 条件变更时忘记同步更新 COUNT 查询,或者没意识到 ORDER BY 缺失导致分页跳跃。这些地方一出错,前端翻页就“丢数据”或“重复刷”。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










