web-dev-qa-db-fra.com

Le robot Facebook frappe fort mon serveur et ignore les directives. Accéder aux mêmes ressources plusieurs fois

Le crawler de Facebook frappe mes serveurs plusieurs fois par seconde et semble ignorer à la fois l'en-tête Expires et la propriété og: ttl.

Dans certains cas, il accède à la même ressource image og: plusieurs fois en l'espace de 1 à 5 minutes. Dans un exemple, le robot d'exploration a accédé à la même image 12 fois en 3 minutes en utilisant 12 adresses IP différentes. 

Je n'avais qu'à enregistrer les demandes pendant 10 minutes avant de prendre l'exemple suivant:

Liste des heures et adresses IP des robots d'exploration pour une image:

2018-03-30 15:12:58 - 66.220.156.145
2018-03-30 15:13:13 - 66.220.152.7
2018-03-30 15:12:59 - 66.220.152.100
2018-03-30 15:12:18 - 66.220.155.248
2018-03-30 15:12:59 - 173.252.124.29
2018-03-30 15:12:15 - 173.252.114.118
2018-03-30 15:12:42 - 173.252.85.205
2018-03-30 15:13:01 - 173.252.84.117
2018-03-30 15:12:40 - 66.220.148.100
2018-03-30 15:13:10 - 66.220.148.169
2018-03-30 15:15:16 - 173.252.99.50
2018-03-30 15:14:50 - 69.171.225.134

Qu'est-ce que l'og: image d'après la documentation de Facebook

L'URL de l'image qui apparaît lorsque quelqu'un partage le contenu avec Facebook. Voir ci-dessous pour plus d'informations et consulter nos meilleures pratiques guide pour apprendre à spécifier une image d’aperçu de haute qualité.

Les images que j'utilise dans og: image ont un en-tête Expires défini sur +7 jours dans le futur. Dernièrement, j'ai changé cela pour +1 an dans le futur. Aucun réglage ne semble faire la différence. Les en-têtes que le robot semble ignorer:

Cache-Control: max-age=604800
Content-Length: 31048
Content-Type: image/jpeg
Date: Fri, 30 Mar 2018 15:56:47 GMT
Expires: Sat, 30 Mar 2019 15:56:47 GMT
Pragma: public
Server: nginx/1.4.6 (Ubuntu)
Transfer-Encoding: chunked
X-Powered-By: PHP/5.5.9-1ubuntu4.23

Selon la documentation de Object Properties de Facebook , la propriété og: ttl est: 

Quelques secondes avant que cette page ne soit refaite. Utilisez ceci pour évaluer la limite les robots d'exploration de contenu Facebook. La valeur minimale autorisée est 345600 secondes (4 jours); si vous définissez une valeur inférieure, le minimum sera utilisé . Si vous n'incluez pas cette balise, le ttl sera calculé à partir du fichier "Expires" en-tête renvoyé par votre serveur Web, sinon ce sera défaut à 7 jours.

J'ai défini cette propriété og: ttl sur 2419200, soit 28 jours plus tard.

J'ai été tenté d'utiliser quelque chose comme ceci:

header("HTTP/1.1 304 Not Modified"); 
exit;

Mais je crains que Crawler de Facebook n’ignore l’en-tête et marque l’image comme brisée, supprimant ainsi l’aperçu de l’image de l’histoire partagée.

Une vidéo montrant la vitesse à laquelle ces requêtes du Crawler arrivent.

Y a-t-il un moyen d'empêcher le robot d'exploration de revenir si rapidement sur ces ressources?

Exemple de code montrant à quoi ressemblent mes propriétés de graphique ouvert et de méta:

<meta property="fb:app_id" content="MyAppId" />
<meta property="og:locale" content="en_GB" />
<meta property="og:type" content="website" />
<meta property="og:title" content="My title" />
<meta property="og:description" content="My description" />
<meta property="og:url" content="http://example.com/index.php?id=1234" />
<link rel="canonical" href="http://example.com/index.php?id=1234" />
<meta property="og:site_name" content="My Site Name" />
<meta property="og:image" content="http://fb.example.com/img/image.php?id=123790824792439jikfio09248384790283940829044" />
<meta property="og:image:width" content="940"/>
<meta property="og:image:height" content="491"/>
<meta property="og:ttl" content="2419200" />
12
Wayne Whitty

Après avoir essayé presque tout le reste avec la mise en cache, les en-têtes et le reste, la seule chose qui a sauvé nos serveurs du robot Facebook "trop ​​enthousiaste" (user agent facebookexternalhit) était simplement refuser l'accès et renvoyer HTTP/1.1 429 Too Many Requests Réponse HTTP , lorsque le robot "a trop exploré".

Certes, nous voulions que le robot d'exploration crawle des milliers d'images, mais le robot Facebook était pratiquement en mode DDOS sur notre serveur avec des dizaines de milliers de demandes (oui, les mêmes URL toujours et encore)} , par heure. Je me souviens que c’était 40 000 requêtes par heure d’adresses IP différentes de Facebook utilisant l’agent facebookexternalhit à un moment donné.

Nous ne voulions pas bloquer complètement le robot d'exploration et bloquer par adresse IP n'était pas non plus une option. Nous avions seulement besoin du robot FB pour reculer (assez) un peu.

C'est un morceau de code PHP que nous utilisions auparavant:

.../images/index.php

<?php

// Number of requests permitted for facebook crawler per second.
const FACEBOOK_REQUEST_THROTTLE = 5;
const FACEBOOK_REQUESTS_JAR = __DIR__ . '/.fb_requests';
const FACEBOOK_REQUESTS_LOCK = __DIR__ . '/.fb_requests.lock';

function handle_lock($lockfile) {
    flock(fopen($lockfile, 'w'), LOCK_EX);
}

$ua = $_SERVER['HTTP_USER_AGENT'] ?? false;
if ($ua && strpos($ua, 'facebookexternalhit') !== false) {

    handle_lock(FACEBOOK_REQUESTS_LOCK);

    $jar = @file(FACEBOOK_REQUESTS_JAR);
    $currentTime = time();
    $timestamp = $jar[0] ?? time();
    $count = $jar[1] ?? 0;

    if ($timestamp == $currentTime) {
        $count++;
    } else {
        $count = 0;
    }

    file_put_contents(FACEBOOK_REQUESTS_JAR, "$currentTime\n$count");

    if ($count >= FACEBOOK_REQUEST_THROTTLE) {
        header("HTTP/1.1 429 Too Many Requests", true, 429);
        header("Retry-After: 60");
        die;
    }

}

// Everything under this comment happens only if the request is "legit". 

$filePath = $_SERVER['DOCUMENT_ROOT'] . $_SERVER['REQUEST_URI'];
if (is_readable($filePath)) {
    header("Content-Type: image/png");
    readfile($filePath);
}

Vous devez également configurer la réécriture pour transmettre toutes les demandes adressées à vos images à ce script PHP:

.../images/.htaccess (si vous utilisez Apache)

RewriteEngine On
RewriteRule .* index.php [L] 

Il semble que le robot "ait compris cette approche" etréduit effectivement le taux de tentativesde des dizaines de milliers demandes par heure à des centaines/milliers demandes par heure.

9
Smuuf

L'envoi aveugle de 304 Not Modified header n'a pas beaucoup de sens et peut encore plus confondre le robot d'exploration de Facebook. Si vous décidez vraiment de bloquer une requête, vous pouvez considérer l'en-tête 429 Too Many Requests - il indiquera au moins clairement le problème.

Comme solution plus douce, vous pouvez essayer:

  • Ajoutez un en-tête Last-Modified avec une valeur statique. Le robot de Facebook peut être assez intelligent pour détecter que, pour modifier constamment le contenu, il doit ignorer l'en-tête Expires, mais pas assez pour gérer correctement l'en-tête manquant.
  • Ajoutez un en-tête ETag avec le support correct 304 Not Modified.
  • Changez l'en-tête Cache-Control en max-age=315360000, public, immutable si l'image est statique.

Vous pouvez également envisager de sauvegarder une image en cache et de la servir via un serveur Web sans impliquer PHP. Si vous changez les URL en quelque chose comme http://fb.example.com/img/image/123790824792439jikfio09248384790283940829044 Vous pouvez créer un repli pour les fichiers inexistants en réécrivant les règles:

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^img/image/([0-9a-z]+)$ img/image.php?id=$1 [L]

Seule la première demande doit être traitée par PHP, ce qui économise le cache pour l’URL demandée (par exemple dans /img/image/123790824792439jikfio09248384790283940829044). Ensuite, pour toutes les autres requêtes, le serveur Web devrait s’occuper de servir le contenu du fichier en cache, d’envoyer les en-têtes appropriés et de manipuler 304 Not Modified. Vous pouvez également configurer nginx pour rate limitation - cela devrait être plus efficace que de déléguer des images de serveurs à PHP.

3
rob006

Il semblerait que les robots de Facebook ne soient pas toujours aussi respectueux. Dans le passé, nous avons implémenté la suggestion suivante: trafic excessif de facebookexternalhit bot

Ce n'est pas la meilleure solution car ce serait bien que Facebook limite le nombre de demandes mais ce n'est clairement pas le cas. 

3
Simon R

J'ai reçu Word de l'équipe Facebook eux-mêmes. J'espère que cela apportera des éclaircissements sur la manière dont le robot traite les URL d'image. 

Ici ça va:

Le Crawler traite les URL d’image différemment des autres URL.

Nous grattons des images plusieurs fois parce que nous avons différents physiques régions, dont chacune doit récupérer l'image. Depuis que nous avons environ 20 régions différentes, le développeur doit s'attendre à environ 20 appels pour chaque image. Une fois que nous faisons ces demandes, ils restent dans notre cache pendant environ un mois - nous devons fréquemment reprendre ces images pour éviter les abus sur la plateforme (un acteur malveillant pourrait nous amener à gratter une image bénigne puis à la remplacer par une image offensive).

Donc, en gros, vous devez vous attendre à ce que l’image spécifiée dans og: image soit touchée 20 fois après son partage. Puis, un mois plus tard, il sera à nouveau gratté.

2
Wayne Whitty

Si les robots d'exploration ignorent vos en-têtes de cache, vous pouvez utiliser l'en-tête "ETag" pour renvoyer les réponses 304 correctes et réduire la charge de votre serveur.

La première fois que vous générez une image, calculez le hachage de cette image (par exemple, à l'aide de md5) en tant qu'en-tête de réponse "ETag". Si votre serveur reçoit une demande avec l'en-tête "If-None-Match", vérifiez si vous avez déjà renvoyé ce hachage. Si la réponse est oui, renvoyez une réponse 304. Sinon, générez l'image.

Vérifier si vous avez déjà renvoyé un hachage donné (tout en évitant de générer à nouveau l'image) signifie que vous devez stocker le hachage quelque part ... Vous pouvez peut-être enregistrer les images dans un dossier tmp et utiliser le hachage comme nom de fichier?

Plus d'infos sur les en-têtes "ETag" + "If-None-Match" .

0
Rober MH

La documentation de Facebook en particulier États "Les images sont mises en cache en fonction de l’URL et ne seront pas mises à jour à moins que l’URL ne soit modifiée." . Cela signifie que les en-têtes ou les balises méta que vous ajoutez n’a pas d'importance, le bot est supposé mettre en cache l'image de toute façon.

Cela m'a fait penser:

  1. Chaque utilisateur partage-t-il une URL légèrement différente de votre page? Cela fera que l'image de partage sera re-mise en cache à chaque fois.
  2. Votre image de partage est-elle accessible à l'aide d'une URL légèrement différente?
  3. Peut-être que l'image est liée différemment quelque part?

Je surveillais les journaux de page et voyais exactement ce qui se passait - si l'URL de la page ou l'URL de l'image était même légèrement différent, le mécanisme de mise en cache ne fonctionnerait pas . Heureusement, cela ne semble pas être un type d'en-tête/balises d'émission.

0
Walter White

Selon Facebook documentation , seul Facebot crawler respecte les directives d'analyse. Cependant, ils suggèrent aussi que

Vous pouvez cibler l'un de ces agents d'utilisateurs pour servir le robot à un version non publique de votre page qui ne contient que des métadonnées et aucun fichier contenu. Cela aide à optimiser les performances et est utile pour garder le contenu paywalled est sécurisé.

Certaines personnes suggèrent de limiter l'accès à facebookexternalhit, mais je doute que ce soit une bonne idée car cela pourrait empêcher le robot d'exploration de mettre à jour le contenu.

Voir plusieurs hits de différentes adresses IP mais le même bot peut être acceptable, selon leur architecture. Vous devriez vérifier à quelle fréquence la même ressource est explorée. og: c’est ce que la documentation recommande et devrait aider.

0
Emil

@Nico suggère

Nous avons eu les mêmes problèmes sur notre site web/serveur. Le problème était la métabalise og:url. Après l'avoir supprimé, le problème a été résolu pour la plupart des appels à facebookexternalhit.

Donc, vous pouvez essayer de le supprimer et voir si cela résout le problème

0
serv-inc