Blog ·
Un badge qui posait un cookie sur chaque page
Une image de pied de page coûtait vingt-deux points Lighthouse sur tout le site. Le remède n’était pas de la retirer, mais ce qu’un relais doit refuser.
Par Provibr
Le score des bonnes pratiques de notre site vitrine était de 78 sur chaque page. Pas sur une page : sur toutes, la page d’accueil, la page des tarifs, la documentation, l’ensemble, uniformément. Des scores uniformes sont bon signe, car ils veulent dire que la cause se trouve dans quelque chose que toutes les pages partagent.
C’était une balise d’image dans le pied de page. Un badge de référencement de lancement, chargé directement depuis la plateforme qui l’émet, parce que c’est ainsi qu’un badge de ce genre est censé être intégré et parce que le nombre qu’il porte est censé être vivant.
Ce qu’une balise d’image peut faire
Le badge est servi par un hôte d’API placé derrière Cloudflare, et Cloudflare répond aux requêtes avec son cookie de gestion des robots : __cf_bm, SameSite=None, Secure, limité au domaine de l’émetteur du badge. Ce n’est pas une décision du site dont c’est le badge. C’est ce que fait un CDN, sur un SVG, à chaque chargement de page, pour chaque visiteur.
Deux audits Lighthouse réagissent à cela. L’audit des cookies tiers pèse cinq des vingt-huit poids de la catégorie, et un signalement de l’inspecteur en pèse un. Six poids perdus sur une image. Sur les trente-huit mesures de la ronde précédente, c’était tout l’écart entre 78 et 100.
La troisième conséquence est celle qu’aucun score ne capture. L’adresse IP de chaque visiteur partait vers une entreprise avec laquelle il n’avait pas choisi de parler, sur chaque page, en échange d’un nombre dans un pied de page.
Le retirer n’est pas la réponse non plus
Nous avions déjà noté l’arbitrage, dans un commentaire, des mois plus tôt : si vous voulez un jour cela sans bandeau de consentement, héberger le SVG chez vous est la voie. Avec le contre-argument attaché, à savoir qu’une copie hébergée chez soi est une photographie. Le badge existe pour montrer un référencement vivant ; figez les octets et vous avez une image d’un référencement.
Il existe une troisième voie, et elle ne devient évidente qu’une fois séparées deux choses que le navigateur fait en même temps. Le navigateur récupère des octets, et le navigateur établit une connexion. Seule la seconde pose problème.
Le badge vient donc désormais de notre propre origine, sur un chemin de notre propre API, et cette route va chercher l’amont côté serveur. Les mêmes octets. Le navigateur du visiteur fait une requête, vers nous. Il n’y a rien sur le fil sur quoi poser un cookie, car il n’y a aucun tiers dans la page du visiteur. Et le nombre reste vivant, car nous continuons de le demander.
Les bonnes pratiques sont passées de 78 à 100 sur trente-deux des trente-six mesures. Les quatre restantes sont les pages d’articles, qui se tiennent à 96 à cause d’un bouton tiers tout à fait différent, et c’est une décision distincte plutôt qu’un reste.
Ce qu’un relais doit à celui pour qui il relaie
Servir les octets de quelqu’un d’autre depuis votre propre origine change ce qu’ils sont. Un SVG chargé par une balise d’image ne peut pas exécuter de script ; c’est une garantie de la spécification et c’est une bonne garantie. Mais dès l’instant où ces octets viennent de notre domaine, ce qu’ils contiennent est à nous.
La route vérifie donc la réponse avant de la transmettre. Ce contrôle n’est délibérément pas un assainisseur. Un assainisseur essaie de rendre sûr un contenu dangereux ; celui-ci refuse tout ce qui ne ressemble pas au badge que nous connaissons déjà, et la route se rabat sur une copie figée. Le pire des cas est un badge de ce matin plutôt qu’un badge de cette minute, ce qui est un prix qui vaut la peine d’être payé pour ne jamais avoir à raisonner sur ce que la réponse de quelqu’un d’autre pourrait contenir.
Deux des refus portent précisément sur ce pour quoi tout ce changement a été fait. Un SVG peut référencer une image externe, et il peut référencer une ressource externe depuis une déclaration de style. L’un ou l’autre irait chercher un tiers une couche plus bas que la balise que nous venons de retirer, depuis l’intérieur d’un fichier que nous servons comme le nôtre. Un contrôle qui n’aurait cherché que des scripts aurait laissé passer les deux.
Échouer vers une image, exprès
Chaque chemin d’échec renvoie la copie figée avec le statut 200. Erreur réseau, expiration, un statut qui n’est pas 200, un corps auquel le contrôle ne fait pas confiance : tous, 200, avec un badge dedans.
Le raisonnement porte sur l’allure de l’échec. Un 404 ou un 502 sur une image du pied de page de toutes les pages, c’est une icône d’image cassée sur toutes les pages, ce qui se lit comme un site cassé, pour un élément décoratif. Un badge légèrement vieux ne se lit pas du tout.
La compensation est que le chemin d’échec porte un en-tête de cache court là où le chemin de succès en porte un long. Sinon, une panne de cinq minutes en amont épinglerait la copie figée devant tout le monde pendant toute la fenêtre de cache.
Il y a une seule copie figée et elle ne vit délibérément pas comme un fichier dans le répertoire public. En tant que fichier, elle aurait une seconde adresse publique à côté de la route, et une ronde future pourrait raisonnablement y pointer une balise d’image, ce qui supprimerait en silence le comportement vivant que tout cet arrangement est là pour préserver. Gardée comme une constante, la seule façon de la servir est de passer par la route qui tente d’abord le réseau.
Deux caches, deux métiers
Il y a ici deux couches de cache, et les confondre produit un système qui, soit martèle l’amont, soit montre des octets périmés pour toujours.
Le cache de données du cadriciel détient la réponse amont : avec une revalidation de six heures, un visiteur toutes les six heures provoque une requête sortante, quel que soit le trafic. L’en-tête de cache HTTP détient notre réponse, au CDN et dans le navigateur. L’amont pose quatre heures sur sa propre réponse ; six de notre côté est un demi-pas plus large délibéré, pour qu’une panne là-bas ne nous fasse pas tomber sur la copie figée à un rythme de quatre heures.
Un petit piège, qui a coûté une construction. Next lit la configuration de segment de route statiquement dans la source, si bien que l’export de revalidation doit être un nombre littéral. L’écrire comme une expression, même comme une constante déclarée quelques lignes plus bas dans le même fichier, interrompt la construction avec une erreur de configuration de segment invalide. La constante lit désormais depuis l’export plutôt que l’inverse, il n’y a donc toujours qu’un seul nombre.
Le 307 qui était un drapeau de démarrage
La même ronde a passé du temps sur quelque chose qui ressemblait à un défaut de routage et n’en était pas un, et cela mérite d’être consigné car cela avait gâché une ronde entière auparavant.
En faisant tourner la construction de production en local, chaque chemin nu du site vitrine répondait 307 en redirigeant vers lui-même. Pas les chemins localisés, pas les routes d’API : les chemins nus. Cela bloquait la moitié anglaise de chaque balayage de mise en page local depuis des semaines et avait été noté comme un défaut inexpliqué.
C’est la liaison d’hôte. Démarré avec une adresse de bouclage littérale comme nom d’hôte, Next laisse cette valeur telle quelle, alors qu’un nom d’hôte vide ou générique est normalisé en localhost. L’URL initiale et l’origine que calcule l’intergiciel divergent alors, la réécriture reste absolue, le routeur la traite comme externe et y rentre à nouveau. Démarré avec la valeur générique, celle qu’utilise la production, ou avec localhost, tout répond 200.
Il n’y avait rien à réparer. Ce qu’il y avait à faire, c’était d’écrire la bonne ligne de démarrage dans le script, et d’écrire pourquoi, car un défaut qui est en réalité un drapeau sera sinon redécouvert par la personne suivante avec la même assurance.
L’échec que nous avons choisi de ne pas corriger
Une troisième chose issue de la même ronde est une non-réparation délibérée, et celles-là méritent d’être notées au moins aussi soigneusement que les corrections.
Nous avions vu des 404 de fragments sur le terrain : du HTML qui référence des fichiers JavaScript qui n’existent plus. L’explication s’est révélée tenir dans un seul en-tête. La page d’accueil porte une fenêtre de stale-while-revalidate qui se mesure en une année, si bien qu’un nœud de CDN a le droit de servir très longtemps du HTML issu d’une construction plus ancienne, et les noms de fragments dans ce HTML appartiennent à cette construction.
Le bouton est là et nous l’avons laissé tranquille, car cette même copie périmée est ce qui a maintenu le site répondant pendant une boucle de plantage de base de données quinze jours plus tôt. Raccourcir la fenêtre échange un chargement cassé rare contre une panne totale plus rare encore. C’est un vrai arbitrage, il appartient à qui porte le risque, et le travail de la ronde était d’expliquer le mécanisme plutôt que de trancher.
Ce que nous noterions
- Un score uniforme sur toutes les pages désigne quelque chose que toutes les pages partagent. C’est la piste la moins chère que vous obtiendrez.
- Une balise d’image est une connexion, pas seulement des octets. Tout ce qu’un CDN veut faire sur une requête, il le fait aussi sur celle-là.
- L’hébergement chez soi n’est pas la seule solution de rechange à l’intégration. Aller chercher côté serveur préserve le comportement vivant et retire le tiers de la page du visiteur.
- Dès que vous servez les octets de quelqu’un d’autre, ils sont à vous. Vérifiez-les, et vérifiez précisément les références qui rouvriraient le trou que vous venez de fermer.
- Préférez une image périmée à une image cassée. Pour de la décoration, un échec visible coûte plus cher qu’une péremption invisible, tant que la fenêtre de péremption est courte sur le chemin d’échec.
- Ne donnez pas d’adresse publique à la copie figée. Tout ce qui est atteignable finira par être lié, et le chemin vivant sera contourné en silence.
- Sachez quel cache détient quoi. L’un détient la réponse amont, l’autre la vôtre, et leurs fenêtres répondent à des questions différentes.
- Certains rouges sont un drapeau, pas un défaut. Reproduisez le mécanisme avant de réparer le symptôme, et si cela se révèle être votre propre commande de démarrage, dites-le dans le script.
Pour être clair : la route est en production et les scores viennent d’une construction de production locale sur trente-six mesures, pas de données de terrain. L’explication des 404 de fragments est dérivée des en-têtes et n’a pas été reproduite, et la décision sur cette fenêtre de cache appartient à la personne qui porte le risque de disponibilité, pas à la ronde.
Issu du travail de plateforme sur Provibr. Une autre mesure qui était verte pour la mauvaise raison est dans une exception d’accessibilité qui se mesure, et un champ qui portait une intention là où un fait avait sa place est dans une date future n’est pas un calendrier.