摘要
如果您的 Discourse 站点在 iPhone 的 Facebook 应用中通过链接访问时显示为纯文本、无样式的 HTML(无 CSS、无 JavaScript、无功能),原因是 Discourse 的爬虫检测机制错误地将 Facebook 的应用内浏览器识别为机器人。
修复方法是通过 Rails 控制台进行一行代码的修改。
症状
用户从 iPhone 上的 Facebook 应用点击指向您 Discourse 站点的链接时,会看到一个精简的、无样式的 HTML 页面——本质上就是爬虫/无脚本布局。由于没有 JavaScript 运行,图片网格、灯箱和媒体播放器等功能无法使用。同样的链接在 Safari、Chrome 以及 Android 和 iPad 上的 Facebook 应用内浏览器中均能正常工作。
原因
iPhone 上 Facebook 的应用内浏览器在用户代理字符串中包含 facebook 一词,例如:
Mozilla/5.0 (iPhone; CPU iPhone OS 18_7 like Mac OS X) AppleWebKit/605.1.15
(KHTML, like Gecko) Mobile/23D8133 Safari/604.1 MetaIAB Facebook
Discourse 的爬虫检测(CrawlerDetection)会将用户代理与 crawler_user_agents 站点设置进行比对,该设置的默认值包含 facebook:
rss|bot|spider|crawler|facebook|archive|wayback|ping|...
这导致 Discourse 向 Facebook 的应用内浏览器提供静态爬虫布局,而不是完整的 Ember 应用——尽管这实际上是一个真实用户使用的真实浏览器。
您可以通过检查 nginx 访问日志中来自该浏览器的请求来确认此情况,并注意到响应负载大小明显小于正常值(通常约为 5KB,而完整主题页面约为 35KB)。
修复方法
将 MetaIAB 添加到 crawler_check_bypass_agents 站点设置中。该设置专门用于豁免即使匹配爬虫列表的用户代理,使其不受爬虫处理。
注意: crawler_check_bypass_agents 是一个隐藏的站点设置,不会出现在标准管理界面中。必须使用 Rails 控制台。
通过 Rails 控制台
SiteSetting.crawler_check_bypass_agents = "MetaIAB"
如果该设置已有值(例如 cubot),请使用管道符分隔符进行追加:
SiteSetting.crawler_check_bypass_agents = "cubot|MetaIAB"
更改立即生效,无需重启。
为什么这样有效
CrawlerDetection.crawler? 方法结合使用以下三个设置:
non_crawler_user_agents—— 如果用户代理匹配此列表,它可能是真实浏览器crawler_user_agents—— 如果同时匹配此列表,则被视为爬虫crawler_check_bypass_agents—— 如果匹配此列表,则无论其他条件如何,均豁免爬虫处理
Facebook 应用内浏览器的用户代理包含 Safari,匹配 non_crawler_user_agents;同时也包含 facebook,匹配 crawler_user_agents。将 MetaIAB(Facebook 应用内浏览器用户代理中独有的字符串)添加到 crawler_check_bypass_agents 后,Discourse 会向其提供完整的应用程序。
为什么 Android 和 iPad 不受影响
- Android:Facebook 在 Android 上的应用内浏览器发送的用户代理不包含
facebook,因此顺利通过爬虫检测。 - iPad:Facebook 在 iPad 上的应用内浏览器也会触发爬虫布局,但由于 iPad 报告的
window.innerWidth较宽(约 1180px),Discourse 会提供桌面布局,而该布局恰好能正常渲染。iPhone 的窄视口(约 414px)会触发移动布局,而在爬虫模式下,该布局完全无法使用。
附加说明:meta-webindexer 泛滥
另外,Facebook 的网络索引器(meta-webindexer/1.1)可能会向您的站点发送极高频率的请求——可能每小时数千次——且全部指向首页。与 meta-externalagent(负责处理 OG 链接预览,应保持不阻塞)不同,meta-webindexer 对大多数 Discourse 安装似乎没有任何实用价值。
如果您在日志中观察到此类流量,可以通过将其添加到 nginx 的机器人阻止配置中,在 nginx 层面进行拦截:
"~*meta-webindexer" 1;
meta-externalagent 应保持允许,因为它负责在 Facebook 上分享链接时抓取 OG 元数据。