Problème d'affichage de l'URL d'image Cloudflare R2 : explication détaillée et solution

Description du problème

Nous avons récemment constaté un problème d’affichage des images sur le forum, plus précisément :

  • Les miniatures des images ne s’affichent pas correctement.
  • Cliquer sur les images affiche correctement l’image en taille réelle.
  • Les outils de développement du navigateur indiquent des URL d’images incorrectes.

Après investigation, la cause profonde est un nom de domaine incorrect dans les URL des images :

  • URL correcte : https://store.starorigin.cc/optimized/1X/[imageID].jpeg
  • URL incorrecte : https://info.7a4081a2d83d3f43fe6b1be1c926fd1c.r2.cloudflarestorage.com/optimized/1X/[imageID].jpeg

Le système utilise le mauvais nom de domaine du bucket R2 brut au lieu de notre nom de domaine CDN configuré.

Analyse technique

Il s’agit d’un problème connu avec Discourse lors du traitement des images stockées dans Cloudflare R2. Dans certains cas, même lorsque s3_cdn_url est configuré, Discourse peut toujours utiliser l’URL de stockage brute au lieu de l’URL CDN lors de la génération d’images optimisées (comme les miniatures).

Cela pourrait être lié aux facteurs suivants :

  • Version de Discourse
  • La configuration du stockage compatible S3
  • La manière dont les URL sont stockées dans la table OptimizedImage

Solution

La solution la plus simple et la plus efficace consiste à utiliser un composant de thème Discourse pour la réparation côté client. Cela ne nécessite aucune opération de base de données ni modification de la configuration du serveur. Il suffit d’ajouter un court extrait de code JavaScript qui remplace automatiquement les URL incorrectes par les URL correctes dans le navigateur.

Code du composant de thème

import { apiInitializer } from "discourse/lib/api";

export default apiInitializer("0.11.1", (api) => {
  // Corrige les images déjà chargées
  function fixImageUrls() {
    const badDomain = "info.7a4081a2d83d3f43fe6b1be1c926fd1c.r2.cloudflarestorage.com";
    const goodDomain = "store.starorigin.cc";

    // Corrige les images normales
    document.querySelectorAll(`img[src*="${badDomain}"]`).forEach(img => {
      img.src = img.src.replace(badDomain, goodDomain);
    });

    // Corrige les images chargées paresseusement
    document.querySelectorAll(`img[data-src*="${badDomain}"]`).forEach(img => {
      img.setAttribute('data-src', img.getAttribute('data-src').replace(badDomain, goodDomain));
    });

    // Corrige les images d'arrière-plan
    document.querySelectorAll('[style*="background"]').forEach(el => {
      if (el.style.backgroundImage && el.style.backgroundImage.includes(badDomain)) {
        el.style.backgroundImage = el.style.backgroundImage.replace(badDomain, goodDomain);
      }
    });

    // Corrige divers autres attributs potentiels
    ['srcset', 'data-large-src', 'data-small-src', 'data-download-href'].forEach(attr => {
      document.querySelectorAll(`[${attr}*="${badDomain}"]`).forEach(el => {
        el.setAttribute(attr, el.getAttribute(attr).replace(badDomain, goodDomain));
      });
    });
  }

  // Corrige les images dans l'éditeur
  api.decorateCooked($elem => {
    fixImageUrls();
  }, { id: 'fix-r2-image-urls' });

  // Corrige après le chargement initial
  api.onPageChange(() => {
    fixImageUrls();
  });

  // Gère le contenu chargé dynamiquement
  const observer = new MutationObserver(mutations => {
    fixImageUrls();
  });

  // Commence l'observation après le chargement du DOM
  if (document.readyState === "loading") {
    document.addEventListener('DOMContentLoaded', () => {
      fixImageUrls();
      startObserver();
    });
  } else {
    fixImageUrls();
    startObserver();
  }

  function startObserver() {
    observer.observe(document.body, {
      childList: true,
      subtree: true,
      attributes: true,
      attributeFilter: ['src', 'data-src', 'srcset', 'style']
    });
  }
});

Comment le code fonctionne

Ce code effectue les actions suivantes :

  1. Détection complète : Trouve toutes les URL d’images contenant le domaine incorrect.
  2. Gestion de plusieurs éléments : Gère divers éléments et attributs d’images (balises img, images chargées paresseusement, images d’arrière-plan, etc.).
  3. Surveillance dynamique : Utilise un MutationObserver pour surveiller les changements de page, garantissant que le contenu chargé dynamiquement est également corrigé.
  4. Intégration Discourse : S’intègre à l’API Discourse pour gérer divers scénarios spéciaux.

Étapes d’installation

  1. Connectez-vous à votre compte administrateur Discourse.
  2. Accédez à Admin > Personnaliser > Composants de thème.
  3. Cliquez sur le bouton Nouveau.
  4. Sélectionnez l’option Créer un nouveau composant.
  5. Nommez-le “Fix R2 Image URLs” (ou tout autre nom de votre choix).
  6. Dans l’onglet “Javascript”, collez le code ci-dessus.
  7. Cliquez sur le bouton Créer.
  8. Cliquez sur le bouton Activer et choisissez le thème auquel l’appliquer (généralement “Défaut”).

Vérification

Après l’installation :

  1. Actualisez la page du forum.
  2. Affichez les publications contenant des images.
  3. Confirmez que les miniatures s’affichent correctement.
  4. Utilisez les outils de développement de votre navigateur pour vérifier que toutes les requêtes d’images pointent vers le domaine CDN.

Bien qu’une solution côté client soit l’approche la plus simple, la plus rapide et la moins risquée, surtout lorsque l’accès direct au serveur est limité.

Conclusion

Ce simple composant de thème résout efficacement le problème des URL d’images lors de l’intégration de Discourse avec le stockage Cloudflare R2, sans nécessiter de modifications de serveur ni de configurations complexes. Bien qu’il corrige le problème côté client plutôt que de s’attaquer à la cause profonde, il est facile à mettre en œuvre, fournit des résultats immédiats et constitue une solution idéale.

Si votre site Discourse rencontre des problèmes similaires, n’hésitez pas à essayer cette solution.

4 « J'aime »

Est-ce que ce problème n’affecte que le chat ? J’essaie de comprendre l’étendue du problème.

Merci pour votre rapport très utile ici !

1 « J'aime »

Oui, ce bug n’affecte que le chat. Mon fournisseur de services S3 est Cloudflare R2. Lorsque j’envoie une image dans l’interface de chat, l’image ne peut pas utiliser les paramètres de lien CDN par défaut, ce qui entraîne l’échec du chargement de l’image.

1 « J'aime »

Il semble toujours s’agir du même cas que Upload images in chat can't be show normally when use s3 CDN, et une correction a été tentée mais annulée par la suite.