Резюме
Если ваш сайт Discourse при доступе через ссылку в приложении Facebook на iPhone отображается как обычный HTML без стилей — без CSS, без JavaScript и без функционала — причина заключается в ошибке определения роботов в Discourse, которая неверно идентифицирует встроенный браузер Facebook как бота.
Исправление заключается в однострочном изменении через консоль Rails.
Симптомы
Пользователи, переходящие по ссылкам на ваш сайт Discourse из приложения Facebook на iPhone, видят упрощённую страницу HTML без стилей — по сути, макет для роботов или тег noscript. JavaScript не выполняется, поэтому такие функции, как сетки изображений, лайтбоксы и медиаплееры, не работают. Те же ссылки корректно работают в Safari, Chrome, а также во встроенном браузере Facebook на Android и iPad.
Причина
Встроенный браузер Facebook на iPhone определяет себя строкой user-agent, содержащей слово 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) проверяет user-agent на соответствие настройке сайта crawler_user_agents, значение по умолчанию которой включает facebook:
rss|bot|spider|crawler|facebook|archive|wayback|ping|...
Из-за этого Discourse отдаёт встроенному браузеру Facebook статический макет для роботов вместо полного приложения Ember, хотя на самом деле это настоящий браузер, используемый реальным человеком.
Вы можете убедиться в этом, проверив лог доступа nginx на наличие запросов от этого браузера и заметив, что размер ответа значительно меньше обычного (обычно ~5 КБ против ~35 КБ для полной страницы темы).
Исправление
Добавьте MetaIAB в настройку сайта crawler_check_bypass_agents. Эта настройка специально предназначена для исключения user-agent из обработки как роботов, даже если они совпадают со списком роботов.
Примечание: 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— если UA соответствует этому списку, это может быть настоящий браузерcrawler_user_agents— если он также соответствует этому списку, он обрабатывается как роботcrawler_check_bypass_agents— если он соответствует этому списку, он исключается из обработки как робот независимо от других условий
User-agent встроенного браузера Facebook содержит Safari, который соответствует non_crawler_user_agents. Также он содержит facebook, который соответствует crawler_user_agents. Добавление MetaIAB — строки, уникальной для user-agent встроенного браузера Facebook, — в crawler_check_bypass_agents заставляет Discourse отдавать ему полное приложение.
Почему Android и iPad не затронуты
- Android: встроенный браузер Facebook на Android отправляет другой user-agent, не содержащий
facebook, поэтому он проходит проверку на роботов без проблем. - iPad: встроенный браузер Facebook на iPad также вызывает отображение макета для роботов, но поскольку iPad сообщает широкое значение
window.innerWidth(~1180 пикселей), Discourse отдаёт десктопный макет, который оказывается достаточно функциональным. Узкое окно просмотра iPhone (~414 пикселей) вызывает отображение мобильного макета, который в режиме роботов полностью неработоспособен.
Дополнительное примечание: нашествие meta-webindexer
Отдельно стоит отметить, что веб-индексатор Facebook (meta-webindexer/1.1) может отправлять на ваш сайт очень большой объём запросов — возможно, тысячи в час — все они направлены на главную страницу. В отличие от meta-externalagent (который обрабатывает предпросмотры ссылок OG и должен оставаться разблокированным), meta-webindexer, по-видимому, не выполняет никакой полезной функции для большинства установок Discourse.
Если вы наблюдаете такой трафик в своих логах, вы можете заблокировать его на уровне nginx, добавив его в конфигурацию блокировки ботов:
"~*meta-webindexer" 1;
meta-externalagent должен оставаться разрешённым, так как он отвечает за извлечение метаданных OG при публикации ссылок в Facebook.