修正: iPhone の Facebook 内蔵ブラウザで Discourse がスタイルなしの HTML として表示される問題

概要

iPhone の Facebook アプリ内のリンクから Discourse サイトにアクセスした際に、CSS も JavaScript も機能も表示されず、プレーンなスタイルなしの HTML のように見える場合、その原因は、Discourse のクローラー検出機能が、Facebook のアプリ内ブラウザを誤ってボットとして識別していることです。

修正方法は、Rails コンソールを通じて 1 行の変更を行うだけです。


症状

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 アクセスログでこのブラウザからのリクエストを確認し、応答ペイロードサイズが通常よりも劇的に小さい(完全なトピックページでは通常 ~35KB に対して ~5KB 程度)ことに注意することで確認できます。


修正方法

crawler_check_bypass_agents サイト設定に MetaIAB を追加します。この設定は、クローラーリストに一致する場合でも、ユーザーエージェントをクローラー扱いから除外するために特別に設計されています。

注意: crawler_check_bypass_agents は非表示のサイト設定であり、標準的な管理 UI には表示されません。Rails コンソールが必要です。

Rails コンソール経由

SiteSetting.crawler_check_bypass_agents = "MetaIAB"

すでに設定に値がある場合(例:cubot)、パイプ区切りで追加します:

SiteSetting.crawler_check_bypass_agents = "cubot|MetaIAB"

この変更は即座に反映され、再起動は不要です。


なぜこれが機能するのか

CrawlerDetection.crawler? メソッドは、以下の 3 つの設定を組み合わせて使用します:

  1. non_crawler_user_agents — UA がこのリストに一致する場合、それは実際のブラウザである可能性があります
  2. crawler_user_agents — さらにこのリストにも一致する場合、クローラーとして扱われます
  3. crawler_check_bypass_agents — このリストに一致する場合、クローラーリストに一致していても、クローラー扱いから除外されます

Facebook のアプリ内ブラウザの UA には Safari が含まれており、これは non_crawler_user_agents に一致します。また facebook も含まれており、これは crawler_user_agents に一致します。Facebook のアプリ内ブラウザの UA に固有の文字列である MetaIABcrawler_check_bypass_agents に追加することで、Discourse はそれを完全なアプリケーションとして提供します。


なぜ Android と iPad は影響を受けないのか

  • Android: Android の Facebook アプリ内ブラウザは、facebook を含まない異なるユーザーエージェントを送信するため、クローラー検出を問題なく通過します。
  • iPad: iPad の Facebook アプリ内ブラウザもクローラーレイアウトをトリガーしますが、iPad は広い window.innerWidth(約 1180px)を報告するため、Discourse はデスクトップレイアウトを提供します。これはたまたま適切にレンダリングされます。一方、iPhone の狭いビューポート(約 414px)はモバイルレイアウトをトリガーし、クローラーモードでは完全に機能しません。

追加の注記:meta-webindexer の洪水

別途、Facebook の Web インデクサー (meta-webindexer/1.1) が、サイトに対して非常に高い頻度でリクエストを送信する可能性があります(1 時間に数千回に達することもあり、すべてがホームページをターゲットにしています)。OG リンクプレビューを処理しブロックされずに残すべき meta-externalagent とは異なり、meta-webindexer はほとんどの Discourse インストールにとって有用な目的を果たしていないようです。

ログでこのトラフィックを観察した場合、nginx レベルでブロック設定に追加することでブロックできます:

"~*meta-webindexer" 1;

meta-externalagent は、Facebook でリンクが共有された際に OG メタデータをスクレイピングする役割を担っているため、許可されたままにする必要があります。

「いいね!」 2

@shortmort37 さん、ありがとうございます。コアのデフォルト設定を MetaIAB を含むように変更する PR を作成しました。

「いいね!」 5