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 :
- Détection complète : Trouve toutes les URL d’images contenant le domaine incorrect.
- 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.).
- Surveillance dynamique : Utilise un
MutationObserverpour surveiller les changements de page, garantissant que le contenu chargé dynamiquement est également corrigé. - Intégration Discourse : S’intègre à l’API Discourse pour gérer divers scénarios spéciaux.
Étapes d’installation
- Connectez-vous à votre compte administrateur Discourse.
- Accédez à Admin > Personnaliser > Composants de thème.
- Cliquez sur le bouton Nouveau.
- Sélectionnez l’option Créer un nouveau composant.
- Nommez-le “Fix R2 Image URLs” (ou tout autre nom de votre choix).
- Dans l’onglet “Javascript”, collez le code ci-dessus.
- Cliquez sur le bouton Créer.
- Cliquez sur le bouton Activer et choisissez le thème auquel l’appliquer (généralement “Défaut”).
Vérification
Après l’installation :
- Actualisez la page du forum.
- Affichez les publications contenant des images.
- Confirmez que les miniatures s’affichent correctement.
- 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.
