多数简单搜索场景用 get 更合理,因其参数可缓存、可分享、符合 rest 语义;gin 中通过 c.query("q") 直接获取 query 参数,无需额外绑定,而 post 需 c.shouldbindjson() 或 c.postform(),代码更冗余。

搜索接口该用 GET 还是 POST?
多数简单搜索场景用 GET 更合理——参数可缓存、可分享、符合 REST 语义。除非搜索条件字段极多(比如带复杂过滤器或分页游标),或者含敏感内容(如用户 ID 列表),才考虑 POST + body 提交。
Gin 默认对 GET 请求的 query 参数解析友好,c.Query("q") 直接取值,无需额外绑定;而 POST 需调用 c.ShouldBindJSON() 或手动解析 c.PostForm(),增加冗余代码。
- URL 示例:
/search?q=go&limit=10&offset=0 - 避免在
GET中传 base64 编码的大文本或二进制数据 - 注意 Nginx 或 CDN 可能对 URL 长度有限制(通常 4K–8K),超长 query 会 400
如何安全地接收和校验搜索关键词?
c.Query("q") 拿到的是原始字符串,不等于“可用”。必须做非空、长度、特殊字符控制——尤其防止 SQL 注入或正则 DoS(比如传入 .*.*.*.*)。
建议用白名单方式限制输入:只允许字母、数字、中文、空格、短横线和下划线,且长度 ≤ 50。
- 用
strings.TrimSpace()去首尾空格,空字符串直接返回400 - 用
regexp.MustCompile(`^[a-zA-Z0-9\u4e00-\u9fa5 _-]{1,50}$`)校验(注意编译一次复用,别放 handler 里) - 若业务允许模糊匹配,
%keyword%拼 SQL 前务必用数据库驱动的占位符(如db.Query("SELECT * FROM x WHERE name LIKE ?", "%"+q+"%")),绝不字符串拼接
分页参数怎么处理才不容易出错?
Gin 不自动转类型,c.Query("limit") 返回 string,直接 strconv.Atoi 容易 panic。更稳妥的是用 c.GetInt() 或 c.GetIntDefault(),它们内部做了错误转换并返回默认值。
- 推荐写法:
limit := c.GetIntDefault("limit", 20),offset := c.GetIntDefault("offset", 0) - 设硬上限,比如
if limit > 100 { limit = 100 },防恶意拉全量 - 注意 offset 大时性能陡降(MySQL 的
LIMIT 100000, 20仍要扫描前 10 万行),后期应改用游标分页(WHERE id > ? ORDER BY id LIMIT 20)
为什么搜索结果要加 Content-Type 和缓存头?
默认 Gin 返回 JSON 时不显式设 Content-Type: application/json; charset=utf-8,某些旧客户端(如部分 iOS WebView)可能解析失败。另外,纯关键词搜索结果适合缓存,但需区分不同 query。
- 加头:
c.Header("Content-Type", "application/json; charset=utf-8") - 缓存控制:
c.Header("Cache-Control", "public, max-age=300")(5 分钟),避免重复请求相同关键词 - 注意:如果结果依赖用户登录态或实时数据(如库存),就别缓存,或改用
private+no-store
真正麻烦的不是写完这几十行代码,而是后续加高亮、拼音纠错、ES 聚合、查询超时熔断——这些都在 query 解析之后才开始起作用。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











