如何在Golang Web项目中实现分页查询_分页参数设计方法

13次阅读

推荐用 page + size,后端转为 offset + limit;可校验边界防越界,避免前端传过大 offset 导致全表扫描;大数据量时应改用游标分页(如 WHERE created_at

如何在Golang Web项目中实现分页查询_分页参数设计方法

分页参数该用 page + size 还是 offset + limit

推荐在 API 层统一用 pagesize后端转换为 offsetlimit 再传给数据库。这样对前端更友好,也便于做默认值和边界校验。

常见错误是直接把 offset 暴露给前端:用户可能传 offset=9999999 导致全表扫描或超时;而 page=1000&size=20 更容易做上限拦截(比如限制 page )。

  • page 从 1 开始(不是 0),避免前端混淆
  • size 应设硬性上限(如最大 100),防止恶意拉取大量数据
  • 若业务需精确跳转(如“加载更多”无限滚动),可额外支持 cursor 模式,但不要替代 page/size

go 后端如何安全解析并校验分页参数

别用 strconv.Atoi 直接转,要结合 net/httpParseForm 和自定义校验逻辑。重点防空值、负数、超限、非数字。

func parsePagination(r *http.Request) (page, size int, err error) {     r.ParseForm()     page, err = strconv.Atoi(r.FormValue("page"))     if err != nil || page < 1 {         return 0, 0, fmt.Errorf("invalid page: must be >= 1")     }     size, err = strconv.Atoi(r.FormValue("size"))     if err != nil || size < 1 || size > 100 {         return 0, 0, fmt.Errorf("invalid size: must be between 1 and 100")     }     return page, size, nil }

注意:r.FormValue 对重复 key 只取第一个,如果需要支持多值(如 page[]=1&page[]=2),得用 r.Form["page"] 并手动处理。

立即学习go语言免费学习笔记(深入)”;

数据库查询时 offset 性能问题怎么绕开

mysql / PostgreSQL 中 OFFSET 越大越慢,尤其在千万级表上。当 page > 1000offset > 10000 时,必须考虑优化。

  • 用主键/时间戳做游标分页(WHERE created_at )
  • 加覆盖索引,确保 ORDER BYWHERE 字段都在索引中
  • 对管理后台类场景,可缓存总条数和高频页的 offset 映射(如预计算 page 500 → offset 9980)

不要依赖 select count(*) 实时算总数——高并发下它会成瓶颈。改用近似值(如 MySQL 的 EXPLaiN 行数)或异步更新的统计表。

返回分页元信息时字段命名要一致且带单位

前端最怕字段名来回变:totaltotalCounttotal_items 混用。建议固定为:

  • total:总记录数(int)
  • page:当前页码(从 1 开始)
  • size:每页条数
  • pages:总页数((total + size - 1) / size
  • has_next / has_prev:布尔值,比算 page 更直观

示例响应结构(jsON):

{   "data": [...],   "pagination": {     "total": 1247,     "page": 3,     "size": 20,     "pages": 63,     "has_next": true,     "has_prev": true   } }

游标分页则不用 pagespage,改用 next_cursorprev_cursor 字符串,且不返回 total —— 这点很容易被忽略,但必须明确告知前端。

text=ZqhQzanResources