[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fZQY3o65JIYhjgAhXfRsUsXGbmB-S7lNBLu5EnTYIoqs":3,"$fHSmMTHg_viXZNOrO99GBu6fsawmRFgsR5_gPDbiIg1M":24},{"_id":4,"slug":5,"__v":6,"author":7,"body":8,"canonical":9,"category":10,"createdAt":11,"date":12,"description":13,"htmlContent":14,"image":15,"imageAlt":15,"readingTime":16,"tags":17,"title":22,"updatedAt":23},"6a1b09e9aa6b273b0c40f580","passage-http-vers-https-imparfait-mixed-content-sur-les-images-cdn",0,"Equipe Seogard","# Migration HTTPS sabotée : quand le CDN sert encore les images en HTTP\n\nMercredi 14h. L'équipe infrastructure d'un retailer français (12 000 pages, 480K sessions organiques/mois) termine la migration HTTP → HTTPS. Le certificat Let's Encrypt est valide. La redirection 301 globale fonctionne. Le cadenas vert apparaît sur la homepage. Le Slack interne affiche un emoji champagne. Cinq semaines plus tard, Search Console révèle −34% de clics sur les pages catégorie. Le cadenas n'a jamais été vert sur 73% du catalogue.\n\n## Vendredi suivant, 9h12 — le premier signal ignoré\n\nUn développeur front remarque un warning dans la console Chrome sur une fiche produit. Il le mentionne en stand-up. Personne ne relève. Le warning :\n\n```\nMixed Content: The page at 'https://www.example-retailer.fr/chaussures/running-trail-x400' was loaded over HTTPS, but requested an insecure image 'http://cdn.example-retailer.fr/media/products/trail-x400-main.jpg'. This content should also be served over HTTPS.\n```\n\nLe CTO regarde rapidement. Le site affiche bien `https://` dans la barre d'adresse. Le certificat couvre `www.example-retailer.fr`. Conclusion rapide : \"C'est juste un warning, pas un blocage. On s'en occupe au sprint suivant.\"\n\nDeux semaines passent.\n\nLe lead SEO ouvre son rapport Search Console hebdomadaire. Les impressions sur les pages catégorie ont baissé de 18%. Il vérifie les positions : stables. Il vérifie l'indexation : pas de page désindexée. Il pense à un effet saisonnier et note le point dans son dashboard.\n\nSemaine 3. La baisse atteint 27% sur les clics. Les positions commencent à glisser — pas en chute libre, mais un effritement constant. Position moyenne sur les catégories : de 8.2 à 11.4. Les pages produit avec images hero semblent les plus touchées.\n\nLe lead SEO lance un crawl Screaming Frog en mode \"Insecure Content\". 8 427 URLs d'images remontent en `http://`. Toutes pointent vers le même sous-domaine : `cdn.example-retailer.fr`.\n\nLe problème n'est pas le certificat du site. Le problème est le CDN.\n\nLe CDN — un bucket S3 derrière CloudFront, configuré trois ans plus tôt — sert les images sur un domaine séparé. Ce domaine a bien un certificat SSL. Mais les URLs stockées en base de données, dans le CMS (un Magento 2.4), pointent toutes vers `http://cdn.example-retailer.fr/...`. La migration HTTPS du domaine principal n'a jamais touché aux URLs du CDN inscrites dans le catalogue produit.\n\nRésultat : le navigateur charge la page en HTTPS, puis demande chaque image en HTTP. Mixed content passif. Chrome ne bloque pas les images (contrairement au mixed content actif — scripts, iframes). Mais il supprime le cadenas. Et Google enregistre la page comme partiellement non sécurisée.\n\n## Le bug : une URL en dur dans trois couches de la stack\n\nLe diagnostic complet a pris deux jours. Le mixed content venait de trois sources distinctes, toutes liées au même sous-domaine CDN.\n\n### Source 1 — Les URLs produit dans la base Magento\n\nLe champ `media_gallery` de chaque produit stocke le chemin relatif de l'image. Mais la base URL du média est configurée dans `core_config_data` :\n\n```sql\nSELECT * FROM core_config_data WHERE path LIKE '%base_media_url%';\n```\n\nRésultat :\n\n```\n+----------+-------------------------------------------+---------------------------------------------+\n| scope    | path                                      | value                                       |\n+----------+-------------------------------------------+---------------------------------------------+\n| default  | web/unsecure/base_media_url               | http://cdn.example-retailer.fr/media/        |\n| default  | web/secure/base_media_url                 | http://cdn.example-retailer.fr/media/        |\n+----------+-------------------------------------------+---------------------------------------------+\n```\n\nLes deux lignes — `unsecure` et `secure` — pointaient vers `http://`. La migration HTTPS avait mis à jour `web/secure/base_url` et `web/unsecure/base_url` vers `https://www.example-retailer.fr/`, mais personne n'avait touché les URLs média. Le ticket de migration ne mentionnait pas le CDN.\n\n### Source 2 — Le template Luma surchargé\n\nLe thème custom contenait un partial pour les balises Open Graph :\n\n```html\n\u003C!-- app/design/frontend/Custom/theme/Magento_Catalog/templates/product/view/opengraph/general.phtml -->\n\u003Cmeta property=\"og:image\" content=\"http://cdn.example-retailer.fr/media/catalog/product/\u003C?= $block->getImage() ?>\" />\n```\n\nL'URL du CDN était codée en dur dans le template. Même après correction de la config Magento, cette balise aurait continué à émettre du `http://`.\n\n### Source 3 — Les descriptions CMS avec URLs absolues\n\nLes descriptions longues de 2 300 produits contenaient des images insérées via l'éditeur WYSIWYG de Magento. Les URLs avaient été copiées-collées au fil des années :\n\n```html\n\u003Cp>Découvrez notre gamme trail :\u003C/p>\n\u003Cimg src=\"http://cdn.example-retailer.fr/media/wysiwyg/collection-trail-2024.jpg\" alt=\"Collection trail 2024\" />\n\u003Cp>Conçue pour les terrains techniques...\u003C/p>\n```\n\nCes URLs vivaient dans la table `catalog_product_entity_text`. Aucune configuration globale ne pouvait les corriger automatiquement.\n\n### Ce que voyait le navigateur vs ce que voyait Googlebot\n\nDans Chrome, les images s'affichaient normalement. Le navigateur charge le mixed content passif (images, vidéos, audio) même en HTTPS — il retire simplement le cadenas et affiche un warning en console. L'utilisateur moyen ne remarque rien.\n\nGooglebot, lui, voit autre chose. Lors du rendu, le crawler détecte les requêtes HTTP sur une page HTTPS. La page est indexée, mais avec un signal de sécurité dégradé. Depuis que [HTTPS est un signal de ranking](https://developers.google.com/search/docs/crawling-indexing/http-https) — même léger — cette dégradation s'applique à chaque page affectée.\n\nPour vérifier ce que Googlebot percevait, l'équipe a utilisé l'outil d'inspection d'URL dans Search Console. Le rendu montrait les images, mais l'onglet \"Plus d'informations\" listait les ressources chargées en HTTP :\n\n```\nRessources bloquées ou en erreur :\n- http://cdn.example-retailer.fr/media/catalog/product/trail-x400-main.jpg (mixed content)\n- http://cdn.example-retailer.fr/media/catalog/product/trail-x400-sole.jpg (mixed content)\n[... 6 ressources supplémentaires sur cette page]\n```\n\n### Pourquoi les tests pré-migration n'avaient rien vu\n\nL'équipe avait testé la migration HTTPS sur un staging. Mais le staging utilisait un CDN différent — un bucket de dev, déjà en HTTPS. Le test passait. La checklist de migration incluait \"Vérifier le certificat SSL\" et \"Tester les redirections 301\". Elle n'incluait pas \"Auditer les URLs d'assets sur domaines tiers\".\n\nLe rapport Lighthouse du staging affichait un score sécurité parfait. Le rapport Lighthouse de la production aussi — Lighthouse teste la page courante dans le navigateur actuel, pas le comportement de Googlebot face aux mixed content passifs.\n\nScreaming Frog en mode standard ne flag pas le mixed content par défaut. Il faut activer l'option \"Check Insecure Content\" dans Configuration > Spider > Advanced, ou utiliser un custom search sur les réponses HTML pour `src=\"http://`. L'équipe ne l'avait pas fait.\n\nUn audit complet via la commande CLI suivante aurait permis de détecter le problème en moins de cinq minutes sur un export HTML :\n\n```bash\n# Chercher toutes les références HTTP dans les pages rendues\ncurl -s https://www.example-retailer.fr/chaussures/running-trail-x400 \\\n  | grep -oP 'src=\"http://[^\"]+' \\\n  | sort -u\n```\n\nRésultat attendu :\n\n```\nsrc=\"http://cdn.example-retailer.fr/media/catalog/product/trail-x400-main.jpg\nsrc=\"http://cdn.example-retailer.fr/media/catalog/product/trail-x400-sole.jpg\nsrc=\"http://cdn.example-retailer.fr/media/catalog/product/trail-x400-lace.jpg\n```\n\nSur un site de 12 000 pages, cette vérification pouvait être scriptée sur un sitemap complet. Elle ne l'a pas été.\n\n## Le fix : trois corrections, une purge, et beaucoup de patience\n\n### Correction 1 — Config Magento `core_config_data`\n\n```sql\nUPDATE core_config_data\nSET value = 'https://cdn.example-retailer.fr/media/'\nWHERE path IN (\n  'web/unsecure/base_media_url',\n  'web/secure/base_media_url'\n);\n```\n\nSuivi d'un flush du cache Magento :\n\n```bash\nphp bin/magento cache:flush\nphp bin/magento cache:clean\nphp bin/magento indexer:reindex\n```\n\nCette correction a couvert environ 6 100 des 8 427 URLs d'images problématiques — celles générées dynamiquement par Magento à partir du chemin relatif + la base URL.\n\n### Correction 2 — Template Open Graph\n\nLe partial a été réécrit pour utiliser la méthode native de Magento :\n\n```php\n\u003C!-- app/design/frontend/Custom/theme/Magento_Catalog/templates/product/view/opengraph/general.phtml -->\n\u003C?php\n$imageUrl = $block->getImage()->getImageUrl();\n// Force HTTPS si le CDN est configuré correctement\n$imageUrl = str_replace('http://', 'https://', $imageUrl);\n?>\n\u003Cmeta property=\"og:image\" content=\"\u003C?= $escaper->escapeUrl($imageUrl) ?>\" />\n```\n\nLe `str_replace` en filet de sécurité peut sembler brutal. Mais dans le contexte d'une correction d'urgence avec un CDN qui supporte déjà HTTPS, c'est le patch le plus sûr. L'équipe a ajouté un TODO pour passer à `$block->getImage()->getSecureUrl()` au sprint suivant.\n\n### Correction 3 — URLs en dur dans les descriptions produit\n\nCelle-ci était la plus lourde. 2 300 produits avec des URLs `http://` dans le champ description. Un script SQL ciblé :\n\n```sql\nUPDATE catalog_product_entity_text\nSET value = REPLACE(value, 'http://cdn.example-retailer.fr/', 'https://cdn.example-retailer.fr/')\nWHERE value LIKE '%http://cdn.example-retailer.fr/%';\n```\n\nAvant exécution, l'équipe a compté les lignes impactées :\n\n```sql\nSELECT COUNT(*) FROM catalog_product_entity_text\nWHERE value LIKE '%http://cdn.example-retailer.fr/%';\n-- Résultat : 3 847 lignes (certains produits avaient plusieurs attributs texte)\n```\n\nBackup complet de la table avant le `UPDATE`. Vérification post-exécution sur 50 produits aléatoires.\n\n### Purge CDN et cache Varnish\n\nLe CDN (CloudFront) cachait les headers de la réponse. Même après correction, les anciennes pages HTML avec les URLs `http://` restaient en cache Varnish côté serveur et en cache CloudFront côté CDN.\n\n```bash\n# Invalidation CloudFront complète\naws cloudfront create-invalidation \\\n  --distribution-id E1XXXXXXXXXX \\\n  --paths \"/*\"\n\n# Purge Varnish\nvarnishadm \"ban req.url ~ .\"\n```\n\nL'invalidation CloudFront a pris 12 minutes pour se propager sur tous les edge locations.\n\n### Ajout d'un header CSP en mode report\n\nPour détecter tout mixed content résiduel, l'équipe a ajouté un header Content-Security-Policy en mode report-only :\n\n```\nContent-Security-Policy-Report-Only: default-src https:; report-uri /csp-report-endpoint\n```\n\nCe header ne bloque rien, mais envoie un rapport JSON à chaque violation. En 48h, l'équipe a identifié 34 URLs supplémentaires avec du mixed content — des images de blog insérées par l'équipe marketing via un plugin WordPress alimentant une section éditoriale du Magento.\n\n### Récupération du trafic\n\nLa timeline de récupération :\n\n- **Jour 0** : déploiement des trois corrections + purge cache.\n- **Jour 3** : Search Console arrête de signaler de nouvelles pages avec mixed content.\n- **Jour 7** : les premières pages corrigées sont re-crawlées. L'inspection d'URL ne montre plus de ressources HTTP.\n- **Jour 14** : les positions commencent à revenir. Position moyenne catégories : 10.1 (vs 11.4 au pic de la baisse).\n- **Jour 28** : retour à 9.0 de position moyenne. Clics à −12% par rapport au niveau pré-incident.\n- **Jour 42** : stabilisation à −5%. L'équipe attribue le delta résiduel à la saisonnalité et au [core update de mai 2026](/blog/google-begins-rolling-out-may-2026-core-update-via-sejournal-mattgsouthern) qui a redistribué certaines positions.\n\nSix semaines pour récupérer ce qu'un `REPLACE` SQL aurait prévenu en cinq minutes le jour de la migration.\n\n### Process ajoutés post-incident\n\nL'équipe a intégré trois garde-fous :\n\n1. **Checklist de migration étendue** : chaque migration de protocole ou de domaine inclut désormais un audit `grep` sur les URLs d'assets dans la base, les templates, et les contenus CMS. Ce point rejoint les recommandations décrites dans notre article sur le [stress test des environnements de staging](/blog/how-to-stress-test-a-staging-environment-to-surface-risks-pre-launch-ask-an-seo-via-sejournal-helenpollitt1).\n\n2. **Header CSP en production** : un `Content-Security-Policy: upgrade-insecure-requests` permanent qui force le navigateur à transformer toute requête `http://` en `https://`. Ce n'est pas un fix — c'est un filet de sécurité. Le header ne change pas ce que Googlebot voit dans le HTML source. Mais il protège l'expérience utilisateur immédiate.\n\n3. **Crawl Screaming Frog hebdomadaire** avec l'option \"Insecure Content\" activée, et alerte Slack automatique si plus de 0 URLs remontent.\n\nPour les équipes ayant vécu des régressions similaires lors de changements d'architecture URL, les cas documentés sur les [migrations www vers non-www](/blog/migration-www-vers-no-www-google-indexe-les-deux-versions-pendant-3-mois) ou les [canonicals pointant vers le staging](/blog/migration-prestashop-vers-bigcommerce-canonicals-pointent-encore-vers-le-staging) montrent le même pattern : une modification incomplète qui affecte des milliers de pages sans déclencher la moindre alerte.\n\n## Ce qu'on en retient\n\nLe mixed content est un bug de migration paresseux. Pas un problème de certificat, pas un problème de serveur — un problème de checklist incomplète. Le certificat SSL protège le transport. Il ne corrige pas les URLs stockées en base depuis trois ans.\n\nLe pattern est toujours le même : la page principale passe en HTTPS, les assets tiers restent en HTTP, les tests visuels ne détectent rien parce que les navigateurs sont tolérants. Googlebot, lui, note tout.\n\nUn monitoring continu type Seogard détecte ce type de divergence entre le HTML servi et les attentes HTTPS en quelques minutes — pas cinq semaines après le déploiement.\n\nLa vraie leçon : chaque migration de protocole est une migration de données. Et les données vivent dans la base, dans les templates, dans les contenus éditoriaux, et dans le CDN. Pas seulement dans le `.htaccess`.\n```","https://seogard.io/blog/passage-http-vers-https-imparfait-mixed-content-sur-les-images-cdn","Migration","2026-05-30T16:01:45.919Z","2026-05-30","Migration HTTPS réussie, mais les images CDN restent en HTTP. Récit d'un mixed content invisible qui a coûté 34% de clics en 5 semaines.","\u003Ch1>Migration HTTPS sabotée : quand le CDN sert encore les images en HTTP\u003C/h1>\n\u003Cp>Mercredi 14h. L'équipe infrastructure d'un retailer français (12 000 pages, 480K sessions organiques/mois) termine la migration HTTP → HTTPS. Le certificat Let's Encrypt est valide. La redirection 301 globale fonctionne. Le cadenas vert apparaît sur la homepage. Le Slack interne affiche un emoji champagne. Cinq semaines plus tard, Search Console révèle −34% de clics sur les pages catégorie. Le cadenas n'a jamais été vert sur 73% du catalogue.\u003C/p>\n\u003Ch2>Vendredi suivant, 9h12 — le premier signal ignoré\u003C/h2>\n\u003Cp>Un développeur front remarque un warning dans la console Chrome sur une fiche produit. Il le mentionne en stand-up. Personne ne relève. Le warning :\u003C/p>\n\u003Cpre>\u003Ccode>Mixed Content: The page at 'https://www.example-retailer.fr/chaussures/running-trail-x400' was loaded over HTTPS, but requested an insecure image 'http://cdn.example-retailer.fr/media/products/trail-x400-main.jpg'. This content should also be served over HTTPS.\n\u003C/code>\u003C/pre>\n\u003Cp>Le CTO regarde rapidement. Le site affiche bien \u003Ccode>https://\u003C/code> dans la barre d'adresse. Le certificat couvre \u003Ccode>www.example-retailer.fr\u003C/code>. Conclusion rapide : \"C'est juste un warning, pas un blocage. On s'en occupe au sprint suivant.\"\u003C/p>\n\u003Cp>Deux semaines passent.\u003C/p>\n\u003Cp>Le lead SEO ouvre son rapport Search Console hebdomadaire. Les impressions sur les pages catégorie ont baissé de 18%. Il vérifie les positions : stables. Il vérifie l'indexation : pas de page désindexée. Il pense à un effet saisonnier et note le point dans son dashboard.\u003C/p>\n\u003Cp>Semaine 3. La baisse atteint 27% sur les clics. Les positions commencent à glisser — pas en chute libre, mais un effritement constant. Position moyenne sur les catégories : de 8.2 à 11.4. Les pages produit avec images hero semblent les plus touchées.\u003C/p>\n\u003Cp>Le lead SEO lance un crawl Screaming Frog en mode \"Insecure Content\". 8 427 URLs d'images remontent en \u003Ccode>http://\u003C/code>. Toutes pointent vers le même sous-domaine : \u003Ccode>cdn.example-retailer.fr\u003C/code>.\u003C/p>\n\u003Cp>Le problème n'est pas le certificat du site. Le problème est le CDN.\u003C/p>\n\u003Cp>Le CDN — un bucket S3 derrière CloudFront, configuré trois ans plus tôt — sert les images sur un domaine séparé. Ce domaine a bien un certificat SSL. Mais les URLs stockées en base de données, dans le CMS (un Magento 2.4), pointent toutes vers \u003Ccode>http://cdn.example-retailer.fr/...\u003C/code>. La migration HTTPS du domaine principal n'a jamais touché aux URLs du CDN inscrites dans le catalogue produit.\u003C/p>\n\u003Cp>Résultat : le navigateur charge la page en HTTPS, puis demande chaque image en HTTP. Mixed content passif. Chrome ne bloque pas les images (contrairement au mixed content actif — scripts, iframes). Mais il supprime le cadenas. Et Google enregistre la page comme partiellement non sécurisée.\u003C/p>\n\u003Ch2>Le bug : une URL en dur dans trois couches de la stack\u003C/h2>\n\u003Cp>Le diagnostic complet a pris deux jours. Le mixed content venait de trois sources distinctes, toutes liées au même sous-domaine CDN.\u003C/p>\n\u003Ch3>Source 1 — Les URLs produit dans la base Magento\u003C/h3>\n\u003Cp>Le champ \u003Ccode>media_gallery\u003C/code> de chaque produit stocke le chemin relatif de l'image. Mais la base URL du média est configurée dans \u003Ccode>core_config_data\u003C/code> :\u003C/p>\n\u003Cpre class=\"shiki github-dark\" style=\"background-color:#24292e;color:#e1e4e8\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">SELECT\u003C/span>\u003Cspan style=\"color:#F97583\"> *\u003C/span>\u003Cspan style=\"color:#F97583\"> FROM\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> core_config_data \u003C/span>\u003Cspan style=\"color:#F97583\">WHERE\u003C/span>\u003Cspan style=\"color:#F97583\"> path\u003C/span>\u003Cspan style=\"color:#F97583\"> LIKE\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> '%base_media_url%'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">;\u003C/span>\u003C/span>\u003C/code>\u003C/pre>\n\u003Cp>Résultat :\u003C/p>\n\u003Cpre>\u003Ccode>+----------+-------------------------------------------+---------------------------------------------+\n| scope    | path                                      | value                                       |\n+----------+-------------------------------------------+---------------------------------------------+\n| default  | web/unsecure/base_media_url               | http://cdn.example-retailer.fr/media/        |\n| default  | web/secure/base_media_url                 | http://cdn.example-retailer.fr/media/        |\n+----------+-------------------------------------------+---------------------------------------------+\n\u003C/code>\u003C/pre>\n\u003Cp>Les deux lignes — \u003Ccode>unsecure\u003C/code> et \u003Ccode>secure\u003C/code> — pointaient vers \u003Ccode>http://\u003C/code>. La migration HTTPS avait mis à jour \u003Ccode>web/secure/base_url\u003C/code> et \u003Ccode>web/unsecure/base_url\u003C/code> vers \u003Ccode>https://www.example-retailer.fr/\u003C/code>, mais personne n'avait touché les URLs média. Le ticket de migration ne mentionnait pas le CDN.\u003C/p>\n\u003Ch3>Source 2 — Le template Luma surchargé\u003C/h3>\n\u003Cp>Le thème custom contenait un partial pour les balises Open Graph :\u003C/p>\n\u003Cpre class=\"shiki github-dark\" style=\"background-color:#24292e;color:#e1e4e8\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">&#x3C;!-- app/design/frontend/Custom/theme/Magento_Catalog/templates/product/view/opengraph/general.phtml -->\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">&#x3C;\u003C/span>\u003Cspan style=\"color:#85E89D\">meta\u003C/span>\u003Cspan style=\"color:#B392F0\"> property\u003C/span>\u003Cspan style=\"color:#E1E4E8\">=\u003C/span>\u003Cspan style=\"color:#9ECBFF\">\"og:image\"\u003C/span>\u003Cspan style=\"color:#B392F0\"> content\u003C/span>\u003Cspan style=\"color:#E1E4E8\">=\u003C/span>\u003Cspan style=\"color:#9ECBFF\">\"http://cdn.example-retailer.fr/media/catalog/product/\u003C/span>\u003Cspan style=\"color:#FDAEB7;font-style:italic\">&#x3C;\u003C/span>\u003Cspan style=\"color:#9ECBFF\">?= $block->getImage() ?>\"\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> />\u003C/span>\u003C/span>\u003C/code>\u003C/pre>\n\u003Cp>L'URL du CDN était codée en dur dans le template. Même après correction de la config Magento, cette balise aurait continué à émettre du \u003Ccode>http://\u003C/code>.\u003C/p>\n\u003Ch3>Source 3 — Les descriptions CMS avec URLs absolues\u003C/h3>\n\u003Cp>Les descriptions longues de 2 300 produits contenaient des images insérées via l'éditeur WYSIWYG de Magento. Les URLs avaient été copiées-collées au fil des années :\u003C/p>\n\u003Cpre class=\"shiki github-dark\" style=\"background-color:#24292e;color:#e1e4e8\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">&#x3C;\u003C/span>\u003Cspan style=\"color:#85E89D\">p\u003C/span>\u003Cspan style=\"color:#E1E4E8\">>Découvrez notre gamme trail :&#x3C;/\u003C/span>\u003Cspan style=\"color:#85E89D\">p\u003C/span>\u003Cspan style=\"color:#E1E4E8\">>\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">&#x3C;\u003C/span>\u003Cspan style=\"color:#85E89D\">img\u003C/span>\u003Cspan style=\"color:#B392F0\"> src\u003C/span>\u003Cspan style=\"color:#E1E4E8\">=\u003C/span>\u003Cspan style=\"color:#9ECBFF\">\"http://cdn.example-retailer.fr/media/wysiwyg/collection-trail-2024.jpg\"\u003C/span>\u003Cspan style=\"color:#B392F0\"> alt\u003C/span>\u003Cspan style=\"color:#E1E4E8\">=\u003C/span>\u003Cspan style=\"color:#9ECBFF\">\"Collection trail 2024\"\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> />\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">&#x3C;\u003C/span>\u003Cspan style=\"color:#85E89D\">p\u003C/span>\u003Cspan style=\"color:#E1E4E8\">>Conçue pour les terrains techniques...&#x3C;/\u003C/span>\u003Cspan style=\"color:#85E89D\">p\u003C/span>\u003Cspan style=\"color:#E1E4E8\">>\u003C/span>\u003C/span>\u003C/code>\u003C/pre>\n\u003Cp>Ces URLs vivaient dans la table \u003Ccode>catalog_product_entity_text\u003C/code>. Aucune configuration globale ne pouvait les corriger automatiquement.\u003C/p>\n\u003Ch3>Ce que voyait le navigateur vs ce que voyait Googlebot\u003C/h3>\n\u003Cp>Dans Chrome, les images s'affichaient normalement. Le navigateur charge le mixed content passif (images, vidéos, audio) même en HTTPS — il retire simplement le cadenas et affiche un warning en console. L'utilisateur moyen ne remarque rien.\u003C/p>\n\u003Cp>Googlebot, lui, voit autre chose. Lors du rendu, le crawler détecte les requêtes HTTP sur une page HTTPS. La page est indexée, mais avec un signal de sécurité dégradé. Depuis que \u003Ca href=\"https://developers.google.com/search/docs/crawling-indexing/http-https\">HTTPS est un signal de ranking\u003C/a> — même léger — cette dégradation s'applique à chaque page affectée.\u003C/p>\n\u003Cp>Pour vérifier ce que Googlebot percevait, l'équipe a utilisé l'outil d'inspection d'URL dans Search Console. Le rendu montrait les images, mais l'onglet \"Plus d'informations\" listait les ressources chargées en HTTP :\u003C/p>\n\u003Cpre>\u003Ccode>Ressources bloquées ou en erreur :\n- http://cdn.example-retailer.fr/media/catalog/product/trail-x400-main.jpg (mixed content)\n- http://cdn.example-retailer.fr/media/catalog/product/trail-x400-sole.jpg (mixed content)\n[... 6 ressources supplémentaires sur cette page]\n\u003C/code>\u003C/pre>\n\u003Ch3>Pourquoi les tests pré-migration n'avaient rien vu\u003C/h3>\n\u003Cp>L'équipe avait testé la migration HTTPS sur un staging. Mais le staging utilisait un CDN différent — un bucket de dev, déjà en HTTPS. Le test passait. La checklist de migration incluait \"Vérifier le certificat SSL\" et \"Tester les redirections 301\". Elle n'incluait pas \"Auditer les URLs d'assets sur domaines tiers\".\u003C/p>\n\u003Cp>Le rapport Lighthouse du staging affichait un score sécurité parfait. Le rapport Lighthouse de la production aussi — Lighthouse teste la page courante dans le navigateur actuel, pas le comportement de Googlebot face aux mixed content passifs.\u003C/p>\n\u003Cp>Screaming Frog en mode standard ne flag pas le mixed content par défaut. Il faut activer l'option \"Check Insecure Content\" dans Configuration > Spider > Advanced, ou utiliser un custom search sur les réponses HTML pour \u003Ccode>src=\"http://\u003C/code>. L'équipe ne l'avait pas fait.\u003C/p>\n\u003Cp>Un audit complet via la commande CLI suivante aurait permis de détecter le problème en moins de cinq minutes sur un export HTML :\u003C/p>\n\u003Cpre class=\"shiki github-dark\" style=\"background-color:#24292e;color:#e1e4e8\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"># Chercher toutes les références HTTP dans les pages rendues\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#B392F0\">curl\u003C/span>\u003Cspan style=\"color:#79B8FF\"> -s\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> https://www.example-retailer.fr/chaussures/running-trail-x400\u003C/span>\u003Cspan style=\"color:#79B8FF\"> \\\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">  |\u003C/span>\u003Cspan style=\"color:#B392F0\"> grep\u003C/span>\u003Cspan style=\"color:#79B8FF\"> -oP\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> 'src=\"http://[^\"]+'\u003C/span>\u003Cspan style=\"color:#79B8FF\"> \\\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">  |\u003C/span>\u003Cspan style=\"color:#B392F0\"> sort\u003C/span>\u003Cspan style=\"color:#79B8FF\"> -u\u003C/span>\u003C/span>\u003C/code>\u003C/pre>\n\u003Cp>Résultat attendu :\u003C/p>\n\u003Cpre>\u003Ccode>src=\"http://cdn.example-retailer.fr/media/catalog/product/trail-x400-main.jpg\nsrc=\"http://cdn.example-retailer.fr/media/catalog/product/trail-x400-sole.jpg\nsrc=\"http://cdn.example-retailer.fr/media/catalog/product/trail-x400-lace.jpg\n\u003C/code>\u003C/pre>\n\u003Cp>Sur un site de 12 000 pages, cette vérification pouvait être scriptée sur un sitemap complet. Elle ne l'a pas été.\u003C/p>\n\u003Ch2>Le fix : trois corrections, une purge, et beaucoup de patience\u003C/h2>\n\u003Ch3>Correction 1 — Config Magento \u003Ccode>core_config_data\u003C/code>\u003C/h3>\n\u003Cpre class=\"shiki github-dark\" style=\"background-color:#24292e;color:#e1e4e8\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">UPDATE\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> core_config_data\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">SET\u003C/span>\u003Cspan style=\"color:#F97583\"> value\u003C/span>\u003Cspan style=\"color:#F97583\"> =\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> 'https://cdn.example-retailer.fr/media/'\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">WHERE\u003C/span>\u003Cspan style=\"color:#F97583\"> path\u003C/span>\u003Cspan style=\"color:#F97583\"> IN\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> (\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">  'web/unsecure/base_media_url'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">  'web/secure/base_media_url'\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">);\u003C/span>\u003C/span>\u003C/code>\u003C/pre>\n\u003Cp>Suivi d'un flush du cache Magento :\u003C/p>\n\u003Cpre class=\"shiki github-dark\" style=\"background-color:#24292e;color:#e1e4e8\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#B392F0\">php\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> bin/magento\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> cache:flush\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#B392F0\">php\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> bin/magento\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> cache:clean\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#B392F0\">php\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> bin/magento\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> indexer:reindex\u003C/span>\u003C/span>\u003C/code>\u003C/pre>\n\u003Cp>Cette correction a couvert environ 6 100 des 8 427 URLs d'images problématiques — celles générées dynamiquement par Magento à partir du chemin relatif + la base URL.\u003C/p>\n\u003Ch3>Correction 2 — Template Open Graph\u003C/h3>\n\u003Cp>Le partial a été réécrit pour utiliser la méthode native de Magento :\u003C/p>\n\u003Cpre class=\"shiki github-dark\" style=\"background-color:#24292e;color:#e1e4e8\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">&#x3C;!--\u003C/span>\u003Cspan style=\"color:#79B8FF\"> app\u003C/span>\u003Cspan style=\"color:#F97583\">/\u003C/span>\u003Cspan style=\"color:#79B8FF\">design\u003C/span>\u003Cspan style=\"color:#F97583\">/\u003C/span>\u003Cspan style=\"color:#79B8FF\">frontend\u003C/span>\u003Cspan style=\"color:#F97583\">/\u003C/span>\u003Cspan style=\"color:#79B8FF\">Custom\u003C/span>\u003Cspan style=\"color:#F97583\">/\u003C/span>\u003Cspan style=\"color:#79B8FF\">theme\u003C/span>\u003Cspan style=\"color:#F97583\">/\u003C/span>\u003Cspan style=\"color:#79B8FF\">Magento_Catalog\u003C/span>\u003Cspan style=\"color:#F97583\">/\u003C/span>\u003Cspan style=\"color:#79B8FF\">templates\u003C/span>\u003Cspan style=\"color:#F97583\">/\u003C/span>\u003Cspan style=\"color:#79B8FF\">product\u003C/span>\u003Cspan style=\"color:#F97583\">/\u003C/span>\u003Cspan style=\"color:#79B8FF\">view\u003C/span>\u003Cspan style=\"color:#F97583\">/\u003C/span>\u003Cspan style=\"color:#79B8FF\">opengraph\u003C/span>\u003Cspan style=\"color:#F97583\">/\u003C/span>\u003Cspan style=\"color:#79B8FF\">general\u003C/span>\u003Cspan style=\"color:#F97583\">.\u003C/span>\u003Cspan style=\"color:#79B8FF\">phtml\u003C/span>\u003Cspan style=\"color:#F97583\"> -->\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">&#x3C;?\u003C/span>\u003Cspan style=\"color:#79B8FF\">php\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">$imageUrl \u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> $block\u003C/span>\u003Cspan style=\"color:#F97583\">->\u003C/span>\u003Cspan style=\"color:#B392F0\">getImage\u003C/span>\u003Cspan style=\"color:#E1E4E8\">()\u003C/span>\u003Cspan style=\"color:#F97583\">->\u003C/span>\u003Cspan style=\"color:#B392F0\">getImageUrl\u003C/span>\u003Cspan style=\"color:#E1E4E8\">();\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">// Force HTTPS si le CDN est configuré correctement\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">$imageUrl \u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#79B8FF\"> str_replace\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'http://'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">, \u003C/span>\u003Cspan style=\"color:#9ECBFF\">'https://'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">, $imageUrl);\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">?>\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">&#x3C;\u003C/span>\u003Cspan style=\"color:#79B8FF\">meta\u003C/span>\u003Cspan style=\"color:#79B8FF\"> property\u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#9ECBFF\">\"og:image\"\u003C/span>\u003Cspan style=\"color:#79B8FF\"> content\u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#9ECBFF\">\"&#x3C;?= \u003C/span>\u003Cspan style=\"color:#E1E4E8\">$escaper\u003C/span>\u003Cspan style=\"color:#F97583\">->\u003C/span>\u003Cspan style=\"color:#E1E4E8\">escapeUrl\u003C/span>\u003Cspan style=\"color:#9ECBFF\">(\u003C/span>\u003Cspan style=\"color:#E1E4E8\">$imageUrl\u003C/span>\u003Cspan style=\"color:#9ECBFF\">) ?>\"\u003C/span>\u003Cspan style=\"color:#F97583\"> />\u003C/span>\u003C/span>\u003C/code>\u003C/pre>\n\u003Cp>Le \u003Ccode>str_replace\u003C/code> en filet de sécurité peut sembler brutal. Mais dans le contexte d'une correction d'urgence avec un CDN qui supporte déjà HTTPS, c'est le patch le plus sûr. L'équipe a ajouté un TODO pour passer à \u003Ccode>$block->getImage()->getSecureUrl()\u003C/code> au sprint suivant.\u003C/p>\n\u003Ch3>Correction 3 — URLs en dur dans les descriptions produit\u003C/h3>\n\u003Cp>Celle-ci était la plus lourde. 2 300 produits avec des URLs \u003Ccode>http://\u003C/code> dans le champ description. Un script SQL ciblé :\u003C/p>\n\u003Cpre class=\"shiki github-dark\" style=\"background-color:#24292e;color:#e1e4e8\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">UPDATE\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> catalog_product_entity_text\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">SET\u003C/span>\u003Cspan style=\"color:#F97583\"> value\u003C/span>\u003Cspan style=\"color:#F97583\"> =\u003C/span>\u003Cspan style=\"color:#79B8FF\"> REPLACE\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(\u003C/span>\u003Cspan style=\"color:#F97583\">value\u003C/span>\u003Cspan style=\"color:#E1E4E8\">, \u003C/span>\u003Cspan style=\"color:#9ECBFF\">'http://cdn.example-retailer.fr/'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">, \u003C/span>\u003Cspan style=\"color:#9ECBFF\">'https://cdn.example-retailer.fr/'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">)\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">WHERE\u003C/span>\u003Cspan style=\"color:#F97583\"> value\u003C/span>\u003Cspan style=\"color:#F97583\"> LIKE\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> '%http://cdn.example-retailer.fr/%'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">;\u003C/span>\u003C/span>\u003C/code>\u003C/pre>\n\u003Cp>Avant exécution, l'équipe a compté les lignes impactées :\u003C/p>\n\u003Cpre class=\"shiki github-dark\" style=\"background-color:#24292e;color:#e1e4e8\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">SELECT\u003C/span>\u003Cspan style=\"color:#79B8FF\"> COUNT\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(\u003C/span>\u003Cspan style=\"color:#F97583\">*\u003C/span>\u003Cspan style=\"color:#E1E4E8\">) \u003C/span>\u003Cspan style=\"color:#F97583\">FROM\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> catalog_product_entity_text\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">WHERE\u003C/span>\u003Cspan style=\"color:#F97583\"> value\u003C/span>\u003Cspan style=\"color:#F97583\"> LIKE\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> '%http://cdn.example-retailer.fr/%'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">;\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">-- Résultat : 3 847 lignes (certains produits avaient plusieurs attributs texte)\u003C/span>\u003C/span>\u003C/code>\u003C/pre>\n\u003Cp>Backup complet de la table avant le \u003Ccode>UPDATE\u003C/code>. Vérification post-exécution sur 50 produits aléatoires.\u003C/p>\n\u003Ch3>Purge CDN et cache Varnish\u003C/h3>\n\u003Cp>Le CDN (CloudFront) cachait les headers de la réponse. Même après correction, les anciennes pages HTML avec les URLs \u003Ccode>http://\u003C/code> restaient en cache Varnish côté serveur et en cache CloudFront côté CDN.\u003C/p>\n\u003Cpre class=\"shiki github-dark\" style=\"background-color:#24292e;color:#e1e4e8\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"># Invalidation CloudFront complète\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#B392F0\">aws\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> cloudfront\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> create-invalidation\u003C/span>\u003Cspan style=\"color:#79B8FF\"> \\\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#79B8FF\">  --distribution-id\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> E1XXXXXXXXXX\u003C/span>\u003Cspan style=\"color:#79B8FF\"> \\\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#79B8FF\">  --paths\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> \"/*\"\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"># Purge Varnish\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#B392F0\">varnishadm\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> \"ban req.url ~ .\"\u003C/span>\u003C/span>\u003C/code>\u003C/pre>\n\u003Cp>L'invalidation CloudFront a pris 12 minutes pour se propager sur tous les edge locations.\u003C/p>\n\u003Ch3>Ajout d'un header CSP en mode report\u003C/h3>\n\u003Cp>Pour détecter tout mixed content résiduel, l'équipe a ajouté un header Content-Security-Policy en mode report-only :\u003C/p>\n\u003Cpre>\u003Ccode>Content-Security-Policy-Report-Only: default-src https:; report-uri /csp-report-endpoint\n\u003C/code>\u003C/pre>\n\u003Cp>Ce header ne bloque rien, mais envoie un rapport JSON à chaque violation. En 48h, l'équipe a identifié 34 URLs supplémentaires avec du mixed content — des images de blog insérées par l'équipe marketing via un plugin WordPress alimentant une section éditoriale du Magento.\u003C/p>\n\u003Ch3>Récupération du trafic\u003C/h3>\n\u003Cp>La timeline de récupération :\u003C/p>\n\u003Cul>\n\u003Cli>\u003Cstrong>Jour 0\u003C/strong> : déploiement des trois corrections + purge cache.\u003C/li>\n\u003Cli>\u003Cstrong>Jour 3\u003C/strong> : Search Console arrête de signaler de nouvelles pages avec mixed content.\u003C/li>\n\u003Cli>\u003Cstrong>Jour 7\u003C/strong> : les premières pages corrigées sont re-crawlées. L'inspection d'URL ne montre plus de ressources HTTP.\u003C/li>\n\u003Cli>\u003Cstrong>Jour 14\u003C/strong> : les positions commencent à revenir. Position moyenne catégories : 10.1 (vs 11.4 au pic de la baisse).\u003C/li>\n\u003Cli>\u003Cstrong>Jour 28\u003C/strong> : retour à 9.0 de position moyenne. Clics à −12% par rapport au niveau pré-incident.\u003C/li>\n\u003Cli>\u003Cstrong>Jour 42\u003C/strong> : stabilisation à −5%. L'équipe attribue le delta résiduel à la saisonnalité et au \u003Ca href=\"/blog/google-begins-rolling-out-may-2026-core-update-via-sejournal-mattgsouthern\">core update de mai 2026\u003C/a> qui a redistribué certaines positions.\u003C/li>\n\u003C/ul>\n\u003Cp>Six semaines pour récupérer ce qu'un \u003Ccode>REPLACE\u003C/code> SQL aurait prévenu en cinq minutes le jour de la migration.\u003C/p>\n\u003Ch3>Process ajoutés post-incident\u003C/h3>\n\u003Cp>L'équipe a intégré trois garde-fous :\u003C/p>\n\u003Col>\n\u003Cli>\n\u003Cp>\u003Cstrong>Checklist de migration étendue\u003C/strong> : chaque migration de protocole ou de domaine inclut désormais un audit \u003Ccode>grep\u003C/code> sur les URLs d'assets dans la base, les templates, et les contenus CMS. Ce point rejoint les recommandations décrites dans notre article sur le \u003Ca href=\"/blog/how-to-stress-test-a-staging-environment-to-surface-risks-pre-launch-ask-an-seo-via-sejournal-helenpollitt1\">stress test des environnements de staging\u003C/a>.\u003C/p>\n\u003C/li>\n\u003Cli>\n\u003Cp>\u003Cstrong>Header CSP en production\u003C/strong> : un \u003Ccode>Content-Security-Policy: upgrade-insecure-requests\u003C/code> permanent qui force le navigateur à transformer toute requête \u003Ccode>http://\u003C/code> en \u003Ccode>https://\u003C/code>. Ce n'est pas un fix — c'est un filet de sécurité. Le header ne change pas ce que Googlebot voit dans le HTML source. Mais il protège l'expérience utilisateur immédiate.\u003C/p>\n\u003C/li>\n\u003Cli>\n\u003Cp>\u003Cstrong>Crawl Screaming Frog hebdomadaire\u003C/strong> avec l'option \"Insecure Content\" activée, et alerte Slack automatique si plus de 0 URLs remontent.\u003C/p>\n\u003C/li>\n\u003C/ol>\n\u003Cp>Pour les équipes ayant vécu des régressions similaires lors de changements d'architecture URL, les cas documentés sur les \u003Ca href=\"/blog/migration-www-vers-no-www-google-indexe-les-deux-versions-pendant-3-mois\">migrations www vers non-www\u003C/a> ou les \u003Ca href=\"/blog/migration-prestashop-vers-bigcommerce-canonicals-pointent-encore-vers-le-staging\">canonicals pointant vers le staging\u003C/a> montrent le même pattern : une modification incomplète qui affecte des milliers de pages sans déclencher la moindre alerte.\u003C/p>\n\u003Ch2>Ce qu'on en retient\u003C/h2>\n\u003Cp>Le mixed content est un bug de migration paresseux. Pas un problème de certificat, pas un problème de serveur — un problème de checklist incomplète. Le certificat SSL protège le transport. Il ne corrige pas les URLs stockées en base depuis trois ans.\u003C/p>\n\u003Cp>Le pattern est toujours le même : la page principale passe en HTTPS, les assets tiers restent en HTTP, les tests visuels ne détectent rien parce que les navigateurs sont tolérants. Googlebot, lui, note tout.\u003C/p>\n\u003Cp>Un monitoring continu type Seogard détecte ce type de divergence entre le HTML servi et les attentes HTTPS en quelques minutes — pas cinq semaines après le déploiement.\u003C/p>\n\u003Cp>La vraie leçon : chaque migration de protocole est une migration de données. Et les données vivent dans la base, dans les templates, dans les contenus éditoriaux, et dans le CDN. Pas seulement dans le \u003Ccode>.htaccess\u003C/code>.\u003C/p>\n\u003Cpre>\u003Ccode>\u003C/code>\u003C/pre>",null,12,[18,19,20,21],"https","mixed content","cdn","security","Mixed content CDN : HTTPS cassé par des images HTTP","Sat May 30 2026 16:01:45 GMT+0000 (Coordinated Universal Time)",[25,39,52],{"_id":26,"slug":27,"__v":6,"author":7,"canonical":28,"category":10,"createdAt":29,"date":30,"description":31,"image":15,"imageAlt":15,"readingTime":16,"tags":32,"title":37,"updatedAt":38},"6a192bc6aa6b273b0cb63757","migration-webflow-vers-framer-301-hub-and-spoke-perdues-pagerank-dilue","https://seogard.io/blog/migration-webflow-vers-framer-301-hub-and-spoke-perdues-pagerank-dilue","2026-05-29T06:01:42.654Z","2026-05-29","Récit d'une migration Webflow vers Framer où 301 redirects hub-and-spoke disparaissent. Diagnostic, impact sur 90 jours, et fix complet.",[33,34,35,36],"webflow","framer","migration","redirects","Migration Webflow → Framer : 301 perdues, PageRank dilué","Fri May 29 2026 06:01:42 GMT+0000 (Coordinated Universal Time)",{"_id":40,"slug":41,"__v":6,"author":7,"canonical":42,"category":10,"createdAt":43,"date":30,"description":44,"image":15,"imageAlt":15,"readingTime":16,"tags":45,"title":50,"updatedAt":51},"6a19b85daa6b273b0c2a585c","migration-www-vers-no-www-google-indexe-les-deux-versions-pendant-3-mois","https://seogard.io/blog/migration-www-vers-no-www-google-indexe-les-deux-versions-pendant-3-mois","2026-05-29T16:01:33.766Z","Un e-commerce migre de www vers no-www. Sans 301 ni canonical stricts, Google indexe les deux versions pendant 3 mois. Récit, diagnostic, fix.",[46,47,48,49],"www","canonical","crawl budget","duplicate content","Migration www vers no-www : 3 mois d'index dupliqué","Fri May 29 2026 16:01:33 GMT+0000 (Coordinated Universal Time)",{"_id":53,"slug":54,"__v":6,"author":7,"canonical":55,"category":10,"createdAt":56,"date":57,"description":58,"image":15,"imageAlt":15,"readingTime":59,"tags":60,"title":64,"updatedAt":65},"6a17da49aa6b273b0c9fa147","migration-prestashop-vers-bigcommerce-canonicals-pointent-encore-vers-le-staging","https://seogard.io/blog/migration-prestashop-vers-bigcommerce-canonicals-pointent-encore-vers-le-staging","2026-05-28T06:01:45.067Z","2026-05-28","Migration PrestaShop vers BigCommerce : les canonical pointaient vers le staging. Récit du bug, diagnostic technique et fix complet.",11,[61,62,47,63],"prestashop","bigcommerce","staging","BigCommerce : canonicals staging en prod, −38% trafic","Thu May 28 2026 06:01:45 GMT+0000 (Coordinated Universal Time)"]