分页查询需严格校验参数、安全计算offset、统一过滤条件查总数与数据、返回结构化元信息;用(page-1)*limit替代前端offset,limit限10–100,总数与分页查询条件必须一致。

分页查询不是加个 LIMIT 和 OFFSET 就完事——Fiber 本身不提供分页能力,关键在参数校验、SQL 拼接、总数计算和响应结构这四步怎么串起来,漏一环就会返回错乱数据或被恶意刷库。
分页参数怎么从 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被篡改绕过页码逻辑 - 别用
c.Query("page", "1")的默认值兜底——它掩盖了空字符串问题,strconv.Atoi("")会 panic,必须显式判空再转
数据库查询怎么配合 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) - 如果用 GORM,别直接写
db.Offset(offset).Limit(limit)—— 它不校验limit上限,得在外层先做截断
怎么把分页元数据塞进响应体
用户需要知道当前页、总条数、总页数、是否有下一页——这些不能靠前端猜,必须后端计算并返回。别只返回数据列表。
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
立即学习“go语言免费学习笔记(深入)”;
- 先查总数(
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}} - 别把
total同时塞进X-Total-Countheader 和 response body——容易不一致;优先信 header,body 里的只作兼容或调试用
通用分页组件怎么封装才不耦合 Fiber
把分页逻辑硬写在 handler 里,半年后你会在 main.go 里 grep 十分钟找某个 offset 计算。真正可复用的封装,必须剥离 HTTP 上下文。
- 定义一个纯函数:
func Paginate(query string, args []interface{}, page, limit int) (interface{}, int, error),接收原始 SQL 和参数,返回数据切片 + 总数 + error - 或者更工程化:在
repository/层定义接口PageQuery(ctx context.Context, filter Filter, pager Pager) ([]User, int, error),其中Pager是含Page、Limit的结构体 - handler 层只负责调用,不碰 SQL 字符串拼接;service 层不感知
*fiber.Ctx,只返回结构体 - 别在封装里自动写
c.Status(200).JSON()——那会让组件无法用于 CLI 工具或测试 mock
最容易被忽略的是:分页总数查询和数据查询必须共用同一份过滤条件,且事务隔离级别要一致;否则高并发下可能出现“查总数是 100,分页拿不到第 5 页”的情况。这不是框架问题,是业务逻辑没对齐。

















