Beego中间件中不能直接用ctx.Input.UserAgent(),因其仅初始化时读取Header且不更新;应优先从X-Original-User-Agent等可信代理头获取,再fallback到User-Agent,并需手动校验代理IP可信性。

Beego中间件里不能直接用ctx.Input.UserAgent()
Beego的ctx.Input.UserAgent()方法返回的是http.Request.UserAgent字段,它只在请求初始化时从Header读一次,后续中间件若修改了Header(比如反向代理透传了X-Original-User-Agent),这个值就不再更新。所以你在中间件里调它,拿到的可能是被覆盖前的旧值,甚至空字符串。
必须手动从Header取,且优先检查可信代理头
真实场景中,Nginx、Cloudflare等代理常会重写User-Agent,而把原始值放在X-Original-User-Agent或X-Forwarded-For关联的可信头里。正确做法是:
- 先判断请求是否来自可信代理IP(比如通过
ctx.Input.IP()比对白名单) - 若是,尝试读
ctx.Request.Header.Get("X-Original-User-Agent") - 否则 fallback 到
ctx.Request.Header.Get("User-Agent") - 永远不要信任
User-Agent做鉴权或风控决策——它可被任意篡改
BeforeStatic阶段要特别小心
如果你在beego.BeforeStatic阶段写UA提取逻辑(比如拦截/static/xxx.pdf并记录UA),注意:
-
ctx.Input.Param()和ctx.Input.Session都未初始化,调用会panic - 不能用
ctx.Input.UserAgent()——它此时还没被赋值,返回空 - 必须用
ctx.Request.Header.Get("User-Agent"),且确保代理已透传 - 如果代理没配
proxy_set_header User-Agent $http_user_agent;,这里拿到的就是代理自身的UA(如nginx/1.20.1)
封装成可复用的工具函数
避免每个中间件都重复判断逻辑,建议抽成函数:
使用阿里云CLI(API 版本 2024-03-30)操作阿里云云监控服务(CMS)的 AgentLoop ContextStore,适用于用户提及云监控时。
func GetRealUserAgent(ctx *context.Context, trustedProxies []string) string {
ip := ctx.Input.IP()
isTrusted := false
for _, p := range trustedProxies {
if ip == p || strings.HasPrefix(ip, p+"/") {
isTrusted = true
break
}
}
if isTrusted {
if ua := ctx.Request.Header.Get("X-Original-User-Agent"); ua != "" {
return ua
}
}
return ctx.Request.Header.Get("User-Agent")
}
调用时传入你配置的可信代理列表,比如[]string{"10.0.0.1", "192.168.1.0/24"}。别忘了在beego.InsertFilter()注册前确保该函数已定义。
最易忽略的一点:Beego不会自动解析X-Forwarded-For里的多层IP,ctx.Input.IP()默认只取最外层。如果代理链超过一层,得自己解析Header并逐层校验可信段——否则“可信代理”判断就失效了。










