如何在Golang中实现API的简单搜索过滤协议 Go语言动态SQL生成技巧

3次阅读

go http handler中应禁用字符串拼接sql,必须使用database/sql占位符;字段名、排序方向需白名单校验;like模糊搜索由服务端加通配符;sqlx.in需配合rebind并处理nil及分批;空值参数指针接收并显式判断。

如何在Golang中实现API的简单搜索过滤协议 Go语言动态SQL生成技巧

Go HTTP handler里怎么安全拼接查询条件

直接用 fmt.Sprintf 拼 SQL 是最常见也最危险的做法,SQL 注入风险几乎必然存在。哪怕只过滤数字 ID,只要没做类型强转或白名单校验,攻击者就能通过 id=1%20OR%201=1 绕过。

  • 所有外部输入必须进 database/sql 的占位符机制,例如 WHERE name LIKE ?,绝不用字符串拼接
  • 字段名(如 namestatus)不能来自请求参数,必须硬编码或从预定义白名单中取,比如用 map 映射:validFields := map[String]bool{"name": true, "created_at": true}
  • 排序字段和方向(ASC/DESC)同理,禁止直接透传,应转换为枚举或 switch 分支校验
  • LIKE 模糊搜索必须手动加通配符,且只在服务端加:stmt.Query("%" + strings.TrimSpace(q) + "%"),前端不传 %

用 sqlx.In 实现 IN 查询的正确姿势

sqlx.In 看起来省事,但容易卡在参数数量限制和类型转换上。postgresql 默认 65535 个参数,mysql 是 65535(实际受 max_allowed_packet 影响),超了就报 too many SQL variables 错误。

  • 调用前先检查切片长度,超过 1000 就分批查,别指望数据库扛得住
  • sqlx.In 返回的是 (?, ?, ?) 和参数列表,必须配合 sqlx.Rebind 才能适配不同驱动,比如 PostgreSQL 要用 $1, $2 格式
  • 如果传的是 []int64,没问题;但如果是 []Interface{} 里混了 nilsqlx.In 会 panic,得提前过滤掉 nil 值
  • 示例:
    query, args, _ := sqlx.In("SELECT * FROM users WHERE id IN (?)", ids) query = db.Rebind(query) rows, _ := db.Queryx(query, args...)

搜索参数解析时怎么避免空值污染 WHERE 条件

用户没填 status,后端却生成了 AND status = '',结果查不到任何数据——这是空字符串、零值、nil 三者没区分清楚的典型表现。

  • 用指针接收可选参数:type SearchReq Struct { Status *string `json:"status"` },这样能明确区分“未传”和“传了空字符串”
  • 对每个字段单独判断:if req.Status != nil && *req.Status != "",而不是 if req.Status != ""
  • 时间范围字段(start_time/end_time)建议用 *time.Time,并用 req.StartTime.After(time.Time{}) 判断是否有效,因为 time.Time 零值是 0001-01-01
  • 布尔字段别用 bool 类型接收,改用 *bool 或字符串枚举("true"/"false"),否则 JSON 解析失败时默认为 false,逻辑就歪了

为什么不要在 Go 里手写动态 SQL 构建器

自己写个 WhereBuilder 类型,支持链式调用、自动加 AND、去重字段……听起来很酷,但实际维护成本高、易出错、难测,而且掩盖了 SQL 本身的复杂性。

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

  • 90% 的搜索场景用 if + 占位符就够了,清晰、可控、debug 友好
  • 真要复用逻辑,优先封装成带明确语义的函数,比如 buildUserSearchQuery(req *SearchReq) (string, []interface{}),而不是抽象出 Builder 接口
  • ORM(如 GORM)自带的 Where 链式调用看似方便,但生成的 SQL 常含冗余括号、隐式类型转换,线上慢查一挖一个准
  • 如果项目里已有 sqlcent,直接用其生成的类型安全查询方法,比手写动态 SQL 更稳

字段白名单、参数分页、空值判断这三处,最容易在 Code Review 时被跳过,但恰恰是上线后出问题的第一爆点。

text=ZqhQzanResources