Fiber中商品查询路由需区分路径参数(c.Params)和查询参数(c.Query),数字参数须手动转换,响应应使用显式结构体而非fiber.Map,中间件必须return拦截,GORM查询务必传c.Context()。

用 fiber.Get() 注册商品查询路由时,路径参数和查询参数别混了
商品查询接口通常既要支持按 ID 查单个商品(如 /api/products/123),也要支持按名称、分类等条件分页检索(如 /api/products?name=phone&page=1)。Fiber 里这两类参数处理方式完全不同::id 是路径参数,必须用 c.Params("id") 取;而 name、page 是查询参数,得用 c.Query("name") 或 c.Queries() 批量取。
常见错误是把 c.Query("id") 当成路径 ID 用——结果永远为空。另外,c.Query() 返回字符串,数字类参数(如 page、limit)要手动转 int,别直接传给数据库 limit 子句。
-
c.Params("id")仅适用于定义在路由路径里的占位符,比如app.Get("/products/:id", handler) -
c.Query("page", "1")第二个参数是默认值,避免空字符串导致strconv.Atoi("")panic - 如果需要解析嵌套查询参数(如
?filter[category]=phone&filter[stock]=true),Fiber 默认不支持,得用c.Body()+ 手动解析或换url.ParseQuery(c.Request().URI().QueryString())
用 fiber.Map 构造响应体前,先校验字段非空和类型安全
返回商品列表时,很多人直接把数据库 struct 塞进 c.JSON(),但实际生产中常遇到字段为 nil(比如 *string 字段没值)、时间戳格式混乱、或敏感字段(如成本价)未过滤。Fiber 的 fiber.Map 是 map[string]interface{},写起来快,但容易掩盖类型问题。
更稳妥的做法是定义显式的响应结构体,用指针字段接收可空值,并在赋值前做判断。例如商品价格字段如果是 *float64,直接塞进 fiber.Map{"price": product.Price},当 Price == nil 时 JSON 会输出 "price": null,前端可能崩溃——不如统一设为 0 或忽略该 key。
- 避免直接返回 GORM model,新建
ProductResponse结构体,只包含前端需要的字段 - 用
time.Time.Format("2006-01-02T15:04:05Z")格式化时间,别依赖 JSON 序列化的默认 layout - 对字符串字段调用
strings.TrimSpace(),防止前后空格污染前端展示
加中间件做基础校验时,别在 next(c) 前 return 错误响应
比如想限制每分钟最多 10 次商品查询请求,用 fiber.Limiter 很方便。但有人会在中间件里手动检查计数,发现超限后直接 c.Status(429).SendString("too many requests"),然后忘了 return ——结果后续 handler 还会执行,既浪费资源又可能返回 200 成功响应,造成逻辑矛盾。
Fiber 中间件必须明确控制执行流:放行就调 next(c),拦截就必须 return。另外,Limiter 的存储后端默认是内存,重启即清零,生产环境务必配 Redis(用 limiter.New(limiter.Config{Store: redis.New(...)}))。
- 所有中间件函数末尾没有
return,且前面有c.Status().Send(),基本等于埋雷 - 对
/products/:id这类精确查询,可以跳过限流(if !strings.HasPrefix(c.Path(), "/products/") { next(c); return }),避免影响缓存友好的请求 - 用
c.Locals在中间件间传递数据(如用户角色),比全局变量或闭包更清晰
连接数据库时,GORM 的 WithContext() 别漏掉,否则超时和取消不生效
商品查询接口常需关联查分类、库存、图片等表,SQL 执行时间波动大。如果不用 context 控制,一个慢查询卡住整个 goroutine,HTTP 超时(如 Nginx 的 30s)到了,但数据库连接还挂着,资源泄漏风险高。
GORM v2+ 支持 WithContext(c.Context()),这个 c.Context() 是 Fiber 封装的,已集成 HTTP 超时和取消信号。但要注意:必须每次查询都显式传,不能只在初始化时设置一次全局 db 实例。
- 不要写
db.First(&p, id),要写db.WithContext(c.Context()).First(&p, id) - 批量查询用
db.WithContext(c.Context()).Find(&products, "category = ?", cat),避免全表扫描时无上限等待 - 如果用了 GORM 的 Preload 关联加载,同样要链式调用
.WithContext(),否则关联查询不受主 context 约束
return 或漏一次 WithContext(),问题往往在线上压测或流量突增时才暴露。


















