直接读 ctx.GetHeader("User-Agent") 即可,返回 string 类型,大小写不敏感且空值返回空字符串;推荐优于 ctx.Request().UserAgent(),避免手动转换,适用于日志、简单判断或路由分发。

直接读 ctx.GetHeader("User-Agent") 就行
不需要额外解析或中间件,Iris 的 Context 提供了标准的 Header 读取接口。ctx.GetHeader("User-Agent") 返回的是 string 类型,可直接用于日志、判断客户端类型或做简单路由分发。
注意:User-Agent 是 HTTP 规范定义的标准请求头,大小写不敏感,但 Iris 的 GetHeader 内部做了规范化处理,传 "user-agent" 或 "USER-AGENT" 都能命中。
- 如果 header 不存在,返回空字符串
"",不是nil,别用== nil判断 - 移动端、爬虫、浏览器等 UA 字符串通常很长,含空格和斜杠,别直接拼进 SQL 或日志路径(可能引发注入或文件名非法)
- 某些代理或 CDN 可能会覆盖原始 UA,如 Nginx 加了
proxy_set_header User-Agent $http_user_agent;才能透传;若发现值固定为Go-http-client/1.1,大概率是后端服务自己发的请求,不是真实终端
ctx.Request().UserAgent() 和 GetHeader 有啥区别?
两者底层都从 *fasthttp.Request 拿值,但语义不同:ctx.Request().UserAgent() 是 fasthttp 原生方法,返回 []byte;ctx.GetHeader("User-Agent") 是 Iris 封装,自动转成 string 并做了空值兜底。
实际效果几乎一样,但推荐用 GetHeader —— 它更符合 Iris 的抽象层级,且避免手动转 string(ctx.Request().UserAgent())。如果你在性能敏感路径(比如每秒万级请求的埋点),且确定 UA 一定存在,UserAgent() 省一次内存拷贝,但绝大多数场景没必要抠这点。
常见误判:为什么拿到的 UA 总是空?
不是 Iris 的问题,而是请求本身没带这个 header。常见原因:
- 前端 fetch / axios 发请求时没设
headers: { "User-Agent": "xxx" }(不允许手动设置,浏览器会忽略) - cURL 或 Postman 测试时忘了加
-H "User-Agent: test" - 某些内网调用或 gRPC 网关转发时剥离了非必要 header
- 你正在调试的是健康检查探针(如 Kubernetes liveness probe),默认不带 UA
验证方式:在 handler 开头加一行 iris.Log().Infof("raw headers: %+v", ctx.Request().Header),看输出里有没有 UserAgent 字段。
需要解析 UA 字符串?别自己写正则
UA 字符串格式混乱(Chrome/Firefox/Safari/微信/QQ/抖音各有一套),硬解析极易漏 case。真要识别设备类型、OS、浏览器版本,用现成库:
-
github.com/ua-parser/uap-go:最成熟,支持规则热更新 -
github.com/mssola/useragent:轻量,纯 Go,无依赖
示例(uap-go):
parser := uaparser.NewFromSaved()
ua := ctx.GetHeader("User-Agent")
if ua != "" {
client, _ := parser.Parse(ua)
iris.Log().Infof("OS: %s, Browser: %s, Device: %s",
client.OS.Family, client.UserAgent.Family, client.Device.Family)
}
注意:解析过程涉及字符串切片和 map 查找,别在高频接口里无条件调用;建议只对关键路径(如登录、注册)或采样日志做解析。
Iris 不干涉 UA 的读取逻辑,但容易被忽略的一点是:它不会帮你做 UA 黑名单拦截或自动降级——这些必须自己写中间件,且判断逻辑要放在路由匹配之后、控制器执行之前,否则 controller 里拿到的 UA 可能已被篡改(比如某些安全中间件会重写 header)。


















