Beego 框架需通过 beego.BeforeRouter 过滤器解析 User-Agent 字符串(如 Googlebot、Bingbot)识别爬虫,统一转小写后字符串匹配,匹配成功则返回预渲染 HTML 并调用 ctx.Abort() 阻止后续路由执行。

Beego 框架本身不内置爬虫识别或 SEO 路由专用机制,但你可以通过 beego.BeforeRouter 过滤器 + User-Agent 解析 + 动态响应控制,实现对爬虫请求的差异化处理。关键在于:别指望框架自动区分,得自己解析 User-Agent 并提前拦截或改写响应。
如何在 BeforeRouter 中识别主流爬虫
搜索引擎爬虫(如 Googlebot、Bingbot、YandexBot)的 User-Agent 字符串有固定模式,用简单字符串匹配比正则更稳、更快。Beego 的 BeforeRouter 是最早能拿到完整 ctx.Request 的钩子,适合做这种前置判断。
- 直接检查
ctx.Request.Header.Get("User-Agent"),避免调用可能 panic 的ctx.Input.UserAgent() - 匹配时统一转小写,忽略大小写差异:
strings.Contains(strings.ToLower(ua), "googlebot") - 优先匹配确定性强的标识:Googlebot/2.1、BingPreview、YandexBot、DuckDuckBot,避免误判普通浏览器
- 不要依赖
robots.txt解析或 IP 反查——延迟高、不可靠、易被伪造
给爬虫返回静态 HTML 快照(SSR)的典型做法
当检测到爬虫时,常见需求是跳过 SPA 前端路由,直接返回预渲染的 HTML。Beego 本身不提供 SSR,但你可以手动拼接或读取预生成文件:
- 用
io.ReadFile("templates/ssr/" + path + ".html")加载对应路径的静态 HTML 文件(需提前构建好) - 若用模板引擎,调用
beego.BConfig.ViewsPath定位模板目录,再用beego.RenderTemplate渲染(注意:需手动传入数据,无自动上下文) - 必须显式设置
ctx.Output.SetStatus(200)和ctx.Output.Header("Content-Type", "text/html; charset=utf-8"),否则默认可能是application/json - 别忘了
ctx.Abort()阻止后续路由执行,否则可能触发 Controller 的Get()方法造成重复响应
为什么不能用 beego.BeforeStatic 或 beego.BeforeExec 处理爬虫
这两个过滤时机都不适合爬虫响应定制:
-
beego.BeforeStatic只对命中/static/等静态目录的请求生效,而爬虫访问的是业务路径(如/article/123),根本不会进这个钩子 -
beego.BeforeExec已经完成路由匹配、Controller 实例化,甚至可能执行了Prepare(),此时再 Abort 成本高、逻辑混乱,且部分中间件(如日志、统计)可能已记录错误状态 - 只有
beego.BeforeRouter在路由分发前介入,能真正实现“未匹配路由前就决定返回什么”
容易踩的坑:User-Agent 伪造与缓存污染
真实场景中,User-Agent 极易被客户端伪造,单纯靠它做权限或跳转会出问题:
- 别用爬虫 UA 做登录态校验或敏感操作授权——
curl -H "User-Agent: Googlebot/2.1" ...就能绕过 - 如果对爬虫返回了不同内容,务必在响应头加
Cache-Control: private, no-transform,防止 CDN 或代理缓存混合版本(比如把爬虫版 HTML 缓存后返回给普通用户) - 某些爬虫(如微信内嵌浏览器)UA 里含 “MicroMessenger”,但它不是搜索引擎——需要白名单精确控制,而不是黑名单排除
- 测试时用
curl -A "Googlebot/2.1"验证,别只靠浏览器开发者工具改 UA,有些行为(如预加载)仍按真实 UA 执行
最麻烦的其实是缓存策略和内容一致性:一旦你开始为爬虫返回特殊 HTML,就得确保它和前端实际渲染结果一致,否则搜索结果页和用户点击后看到的页面对不上,SEO 反而受损。这点比代码怎么写更值得花时间验证。



















