分页参数需校验:page≤0重置为1,size>100或≤0截断为20,用strconv.Atoi转换并检查error;SQL中禁拼接,须用预处理参数;大数据量时应优先采用游标分页而非OFFSET。

分页参数怎么安全校验
直接用 page 和 size 是常见做法,但不校验会引发越界、性能崩溃或 SQL 注入风险。必须限制范围:比如 page 不能 ≤ 0,size 不能超过 100(业务可调),且要转为整型后立即检查溢出。
-
page默认设为 1,若传 0 或负数,统一重置为 1 -
size默认设为 20,若 > 100 或 ≤ 0,强制截断为 20 - 用
strconv.Atoi转换后,立刻判断 error,避免字符串如"abc"导致 panic - 不要在 SQL 中拼接
page/size,一律走预处理参数(OFFSET ? LIMIT ?)
数据库层如何高效分页(尤其 MySQL)
用 LIMIT offset, size 在数据量大时性能急剧下降,因为 MySQL 仍需扫描前 offset 行。真实场景中,应优先考虑游标分页(cursor-based pagination),即用上一页最后一条记录的主键/时间戳作为下一页起点。
- 传统
OFFSET分页只适合offset 的小数据集;超了就慢 - 游标分页要求排序字段有索引(如
id DESC),且该字段值唯一或组合唯一(如created_at, id) - 接口返回时带
next_cursor字段(如 base64 编码的"123456"),前端下次请求传?cursor=123456 - SQL 示例:
SELECT * FROM posts WHERE id ,其中?是上一页最小 id
API 响应结构怎么设计才利于前端使用
别只返回数据列表,前端需要知道“还能不能翻”、“当前在哪一页”、“总共有多少条”。但总总数(total)在大数据量下查 COUNT(*) 很重,得按场景权衡。
- 必含字段:
data(当前页数据)、has_next(布尔值,比next_page更轻量)、cursor(游标分页时用) - 可选
total:仅当数据量稳定且COUNT查询能命中索引(如覆盖索引)时开启;否则设为null或省略 - 避免返回
page/size,它们是请求参数,不是响应状态;前端自己维护即可 - 错误时统一返回
error字段,不要把分页逻辑错误(如无效 cursor)混进 500
Go 代码里怎么封装分页逻辑不重复写
每次写 OFFSET 计算、参数绑定、count 查询太啰嗦。建议抽一个 Paginator 结构体,把校验、生成 SQL 片段、构造响应三件事包掉。
立即学习“go语言免费学习笔记(深入)”;
- 定义
type Paginator struct { Page, Size, Total int64; Data interface{} },Total可延迟计算 - 提供
paginator.BuildQuery()方法,返回query string和args []interface{},供db.Query直接用 - 提供
paginator.Response()方法,返回 map[string]interface{},含data、has_next等字段 - 游标模式下,
Cursor字段存原始值(如 int64),编码/解码由外层 HTTP handler 处理,Paginator 不碰 base64
游标分页的边界 case 最容易漏:比如最后一页数据刚好等于 size,has_next 却误判为 true;或者 cursor 解码失败没 fallback 到默认值。这些地方不写测试,上线后前端会反复翻到空页。










