应通过正则/(?i)mobile|android|iphone|ipad|ios/匹配User-Agent判断终端类型,优先级为User-Agent > Sec-CH-UA-Mobile > 自定义header,需字段裁剪而非仅格式转换,严格分离判断与权限逻辑。

怎么用 User-Agent 判断移动端还是桌面端
直接读 c.Get("User-Agent"),别信 c.IsMobile() —— Fiber v2/v3 都没这个方法。正则匹配最轻量也最可靠:/(?i)mobile|android|iphone|ipad|ios/。注意 iPad 在新版 Safari UA 里可能不带 Mobile,但含 iPad,所以必须显式列出;Windows Phone 已淘汰,不用管。
微信内置浏览器 UA 含 MicroMessenger,但不能单靠它判断终端类型——得结合 Mobile 或 Sec-CH-UA-Mobile: ?1(Chromium 新标准)交叉验证。真实项目里,小程序后端 UA 是 miniprogram,纯靠 UA 关键词会漏判。
中间件里怎么安全提取和判断来源
自定义中间件函数签名必须是 func(*fiber.Ctx) error,且要显式调用 c.Next() 才能继续流程。别在判断逻辑后忘了 return,否则即使已返回响应,后续 handler 还会执行,导致 panic 或响应覆盖。
- UA 字符串需转小写或用
(?i)正则,避免大小写问题 - 别在中间件里反复调
c.Get("User-Agent")—— 它只是字符串读取,无性能问题,但语义上建议只取一次存到c.Locals - 如果要支持 fallback 判断(比如 header 缺失时查
X-Client-Type),顺序应为:User-Agent>Sec-CH-UA-Mobile> 自定义 header - 不要把 UA 判断和权限校验混在一个中间件里——职责分离更易测试和复用
为什么 Accept 头不能代替来源检测
c.Accepts("json") 只检查请求头 Accept: application/json,和终端类型完全无关。浏览器、curl、Postman 默认都发这个头,它解决的是“要什么格式”,不是“从哪来”。后台管理页用桌面浏览器访问同一 API,或小程序走相同路由,Accept 都一样,但终端行为完全不同。
真要组合多格式 + 多终端,优先级必须是:User-Agent > Sec-CH-UA-Mobile > 自定义 header。把 Accept 当兜底,等于没兜住。
字段裁剪比格式转换更关键
同一个路由返回不同结构,核心不是换 JSON/XML,而是按终端裁剪字段。移动端通常不需要 created_at 微秒时间戳、冗余关联数据或管理类字段(如 last_login_ip)。
推荐做法:
- 定义两个 struct:
UserMobileResp和UserDesktopResp,字段严格按需拆分 - 避免用
map[string]interface{}拼接 —— 类型不安全、IDE 无提示、序列化慢 - 封装转换函数,比如
toMobileUser(u *User) *UserMobileResp,别在 handler 里堆 if-else 赋值 - 移动端最容易漏掉的坑:忘了裁剪嵌套对象里的冗余字段(比如
User.Profile.Settings)
终端适配真正的复杂点不在判断逻辑,而在字段边界的持续收敛——每次加一个新字段,都要同步确认它是否该出现在移动端响应里。


















