Problema de visualización de URL de imagen de Cloudflare R2: explicación detallada y solución

Descripción del problema

Recientemente hemos notado un problema con la visualización de imágenes en el foro, específicamente:

  • Las miniaturas de las imágenes no se muestran correctamente.
  • Al hacer clic en las imágenes, se muestra la imagen a tamaño completo correctamente.
  • Las herramientas de desarrollador del navegador muestran URL de imágenes incorrectas.

Después de la investigación, la causa raíz es un nombre de dominio incorrecto en las URL de las imágenes:

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

El sistema está utilizando el dominio incorrecto del bucket R2 en bruto en lugar de nuestro dominio CDN configurado.

Análisis técnico

Este es un problema conocido con Discourse al manejar imágenes almacenadas en Cloudflare R2. En algunos casos, incluso cuando s3_cdn_url está configurado, Discourse podría seguir utilizando la URL de almacenamiento en bruto en lugar de la URL CDN al generar imágenes optimizadas (como miniaturas).

Esto podría estar relacionado con los siguientes factores:

  • Versión de Discourse
  • La configuración del almacenamiento compatible con S3
  • Cómo se almacenan las URL en la tabla OptimizedImage

Solución

La solución más sencilla y eficaz es utilizar un componente temático de Discourse para la reparación del lado del cliente. Esto no requiere ninguna operación de base de datos ni cambios en la configuración del servidor. Solo implica agregar un pequeño fragmento de código JavaScript que reemplaza automáticamente las URL incorrectas por las correctas en el navegador.

Código del componente temático

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

export default apiInitializer("0.11.1", (api) => {
  // Corregir imágenes ya cargadas
  function fixImageUrls() {
    const badDomain = "info.7a4081a2d83d3f43fe6b1be1c926fd1c.r2.cloudflarestorage.com";
    const goodDomain = "store.starorigin.cc";

    // Corregir imágenes normales
    document.querySelectorAll(`img[src*="${badDomain}"]`).forEach(img => {
      img.src = img.src.replace(badDomain, goodDomain);
    });

    // Corregir imágenes de carga diferida
    document.querySelectorAll(`img[data-src*="${badDomain}"]`).forEach(img => {
      img.setAttribute('data-src', img.getAttribute('data-src').replace(badDomain, goodDomain));
    });

    // Corregir imágenes de fondo
    document.querySelectorAll('[style*="background"]').forEach(el => {
      if (el.style.backgroundImage && el.style.backgroundImage.includes(badDomain)) {
        el.style.backgroundImage = el.style.backgroundImage.replace(badDomain, goodDomain);
      }
    });

    // Corregir varios otros atributos potenciales
    ['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));
      });
    });
  }

  // Corregir imágenes en el editor
  api.decorateCooked($elem => {
    fixImageUrls();
  }, { id: 'fix-r2-image-urls' });

  // Corregir después de la carga inicial
  api.onPageChange(() => {
    fixImageUrls();
  });

  // Manejar contenido cargado dinámicamente
  const observer = new MutationObserver(mutations => {
    fixImageUrls();
  });

  // Comenzar a observar después de que el DOM esté cargado
  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']
    });
  }
});

Cómo funciona el código

Este código realiza las siguientes acciones:

  1. Detección integral: Encuentra todas las URL de imágenes que contienen el dominio incorrecto.
  2. Manejo de múltiples elementos: Maneja varios elementos y atributos de imágenes (etiquetas img, imágenes de carga diferida, imágenes de fondo, etc.).
  3. Monitoreo dinámico: Utiliza un MutationObserver para monitorear los cambios en la página, asegurando que el contenido cargado dinámicamente también se corrija.
  4. Integración con Discourse: Se integra con la API de Discourse para manejar varios escenarios especiales.

Pasos de instalación

  1. Inicie sesión en su cuenta de administrador de Discourse.
  2. Vaya a Admin > Personalizar > Componentes temáticos.
  3. Haga clic en el botón Nuevo.
  4. Seleccione la opción Crear nuevo componente.
  5. Nómbrelo “Corregir URL de imágenes R2” (o el nombre que prefiera).
  6. En la pestaña “Javascript”, pegue el código anterior.
  7. Haga clic en el botón Crear.
  8. Haga clic en el botón Habilitar y elija el tema al que aplicarlo (generalmente “Predeterminado”).

Verificación

Después de la instalación:

  1. Actualice la página del foro.
  2. Vea las publicaciones que contienen imágenes.
  3. Confirme que las miniaturas se muestran correctamente.
  4. Utilice las herramientas de desarrollador de su navegador para verificar que todas las solicitudes de imágenes apunten al dominio CDN.

Si bien una solución del lado del cliente es el enfoque más simple, rápido y de menor riesgo, especialmente cuando el acceso directo al servidor es limitado.

Conclusión

Este sencillo componente temático aborda eficazmente el problema de las URL de imágenes al integrar Discourse con el almacenamiento Cloudflare R2, sin necesidad de cambios en el servidor o configuraciones complejas. Aunque soluciona el problema en el lado del cliente en lugar de abordar la causa raíz, es fácil de implementar, proporciona resultados inmediatos y es una solución ideal.

Si su sitio de Discourse también está experimentando problemas similares, no dude en probar esta solución.

4 Me gusta

¿este problema solo afecta al chat? intentando comprender el alcance.

¡Gracias por tu informe tan útil aquí!

1 me gusta

Sí, este error solo afecta al chat. Mi proveedor de servicios S3 es Cloudflare R2. Cuando envío una imagen en la interfaz de chat, la imagen no puede usar la configuración predeterminada del enlace CDN, lo que provoca que la imagen no se cargue.

1 me gusta

Parece que sigue siendo el mismo caso que en Upload images in chat can't be show normally when use s3 CDN, y se intentó una corrección que luego se revirtió.