Problema na exibição de URL de imagem do Cloudflare R2: explicação detalhada e correção

Descrição do Problema

Recentemente, notamos um problema com a exibição de imagens no fórum, especificamente:

  • As miniaturas das imagens não estão sendo exibidas corretamente.
  • Clicar nas imagens exibe a imagem em tamanho real corretamente.
  • As ferramentas de desenvolvedor do navegador mostram URLs de imagem incorretas.

Após investigação, a causa raiz é um nome de domínio incorreto nas URLs das imagens:

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

O sistema está usando o domínio incorreto do bucket R2 bruto em vez do nosso domínio CDN configurado.

Análise Técnica

Este é um problema conhecido com o Discourse ao lidar com imagens armazenadas no Cloudflare R2. Em alguns casos, mesmo quando s3_cdn_url está configurado, o Discourse pode ainda usar o URL de armazenamento bruto em vez do URL do CDN ao gerar imagens otimizadas (como miniaturas).

Isso pode estar relacionado aos seguintes fatores:

  • Versão do Discourse
  • A configuração do armazenamento compatível com S3
  • Como os URLs são armazenados na tabela OptimizedImage

Solução

A solução mais simples e eficaz é usar um componente de tema do Discourse para reparo no lado do cliente. Isso não requer nenhuma operação de banco de dados ou alterações na configuração do servidor. Envolve apenas a adição de um pequeno trecho de código JavaScript que substitui automaticamente os URLs incorretos pelos corretos no navegador.

Código do Componente de Tema

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

export default apiInitializer("0.11.1", (api) => {
  // Corrige imagens já carregadas
  function fixImageUrls() {
    const badDomain = "info.7a4081a2d83d3f43fe6b1be1c926fd1c.r2.cloudflarestorage.com";
    const goodDomain = "store.starorigin.cc";

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

    // Corrige imagens com carregamento lento (lazy-loaded)
    document.querySelectorAll(`img[data-src*="${badDomain}"]`).forEach(img => {
      img.setAttribute('data-src', img.getAttribute('data-src').replace(badDomain, goodDomain));
    });

    // Corrige imagens de fundo
    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 vários outros atributos potenciais
    ['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 imagens no editor
  api.decorateCooked($elem => {
    fixImageUrls();
  }, { id: 'fix-r2-image-urls' });

  // Corrige após o carregamento inicial
  api.onPageChange(() => {
    fixImageUrls();
  });

  // Lida com conteúdo carregado dinamicamente
  const observer = new MutationObserver(mutations => {
    fixImageUrls();
  });

  // Começa a observar após o DOM ser carregado
  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']
    });
  }
});

Como o Código Funciona

Este código realiza as seguintes ações:

  1. Detecção Abrangente: Encontra todos os URLs de imagem que contêm o domínio incorreto.
  2. Manuseio de Múltiplos Elementos: Lida com vários elementos e atributos de imagem (tags img, imagens com carregamento lento, imagens de fundo, etc.).
  3. Monitoramento Dinâmico: Usa um MutationObserver para monitorar as alterações na página, garantindo que o conteúdo carregado dinamicamente também seja corrigido.
  4. Integração com Discourse: Integra-se com a API do Discourse para lidar com vários cenários especiais.

Passos de Instalação

  1. Faça login na sua conta de administrador do Discourse.
  2. Vá para Admin > Personalizar > Componentes de Tema.
  3. Clique no botão Novo.
  4. Selecione a opção Criar novo componente.
  5. Nomeie-o como “Fix R2 Image URLs” (ou qualquer nome que preferir).
  6. Na aba “Javascript”, cole o código acima.
  7. Clique no botão Criar.
  8. Clique no botão Ativar e escolha o tema ao qual aplicá-lo (geralmente “Padrão”).

Verificação

Após a instalação:

  1. Recarregue a página do fórum.
  2. Visualize postagens que contenham imagens.
  3. Confirme que as miniaturas estão sendo exibidas corretamente.
  4. Use as ferramentas de desenvolvedor do seu navegador para verificar se todas as requisições de imagem estão apontando para o domínio CDN.

Embora uma solução do lado do cliente seja a abordagem mais simples, rápida e de menor risco, especialmente quando o acesso direto ao servidor é limitado.

Conclusão

Este componente de tema simples aborda efetivamente o problema do URL da imagem ao integrar o Discourse com o armazenamento Cloudflare R2, sem a necessidade de alterações no servidor ou configurações complexas. Embora corrija o problema no lado do cliente em vez de abordar a causa raiz, é fácil de implementar, fornece resultados imediatos e é uma solução ideal.

Se o seu site Discourse também estiver enfrentando problemas semelhantes, sinta-se à vontade para experimentar esta solução.

4 curtidas

este problema afeta apenas o chat? estou tentando entender o escopo.

Obrigado pelo seu relatório muito útil aqui!

1 curtida

Sim, este bug afeta apenas o chat. Meu provedor de serviços S3 é o Cloudflare R2. Quando envio uma imagem na interface de chat, a imagem não pode usar as configurações padrão de link de CDN, resultando na falha ao carregar a imagem.

1 curtida

Parece que ainda é o mesmo caso de Upload images in chat can't be show normally when use s3 CDN, e uma correção foi tentada, mas depois revertida.