Discourse R2存储图片URL显示问题详解与修复

Discourse R2存储图片URL显示问题详解与修复

问题描述

近期发现论坛中的图片显示出现异常,具体表现为:

  • 图片缩略图无法正常显示
  • 点击图片后原图可以正常查看
  • 浏览器开发者工具中显示图片URL错误

经排查,问题的根本原因是图片URL的域名错误:

  • 正确URL: https://store.starorigin.cc/optimized/1X/[图片ID].jpeg
  • 错误URL: https://info.7a4081a2d83d3f43fe6b1be1c926fd1c.r2.cloudflarestorage.com/optimized/1X/[图片ID].jpeg

即系统使用了R2存储桶的原始域名,而非我们配置的CDN域名。

技术分析

这是Discourse在处理存储于Cloudflare R2的图片时的一个已知问题。在某些情况下,尽管配置了s3_cdn_url,Discourse仍会在生成优化图像(如缩略图)时使用原始存储URL而非CDN URL。

这可能与以下因素有关:

  • Discourse版本
  • S3兼容存储的配置方式
  • OptimizedImage表中URL的存储方式

解决方案

最简单有效的解决方法是使用Discourse主题组件进行客户端修复。这不需要数据库操作或服务器配置更改,只需添加一段JavaScript代码,在浏览器中自动将错误的URL替换为正确的URL。

主题组件代码

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

export default apiInitializer("0.11.1", (api) => {
  // 修复已加载的图片
  function fixImageUrls() {
    const badDomain = "info.7a4081a2d83d3f43fe6b1be1c926fd1c.r2.cloudflarestorage.com";
    const goodDomain = "store.starorigin.cc";
    
    // 修复常规图片
    document.querySelectorAll(`img[src*="${badDomain}"]`).forEach(img => {
      img.src = img.src.replace(badDomain, goodDomain);
    });
    
    // 修复懒加载图片
    document.querySelectorAll(`img[data-src*="${badDomain}"]`).forEach(img => {
      img.setAttribute('data-src', img.getAttribute('data-src').replace(badDomain, goodDomain));
    });
    
    // 修复背景图片
    document.querySelectorAll('[style*="background"]').forEach(el => {
      if (el.style.backgroundImage && el.style.backgroundImage.includes(badDomain)) {
        el.style.backgroundImage = el.style.backgroundImage.replace(badDomain, goodDomain);
      }
    });
    
    // 修复各种其他可能的属性
    ['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));
      });
    });
  }
  
  // 修复编辑器中的图片
  api.decorateCooked($elem => {
    fixImageUrls();
  }, { id: 'fix-r2-image-urls' });
  
  // 首次加载后修复
  api.onPageChange(() => {
    fixImageUrls();
  });
  
  // 处理动态加载的内容
  const observer = new MutationObserver(mutations => {
    fixImageUrls();
  });
  
  // 在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']
    });
  }
});

代码工作原理

这段代码实现了以下功能:

  1. 全面检测:查找所有包含错误域名的图片URL
  2. 多元素处理:处理各种图片元素和属性(img标签、懒加载图片、背景图片等)
  3. 动态监控:使用MutationObserver监控页面变化,确保动态加载内容也能被修复
  4. Discourse集成:与Discourse API集成,处理各种特殊场景

安装步骤

  1. 登录Discourse管理员账户
  2. 前往 管理员 > 自定义 > 主题组件
  3. 点击 新建 按钮
  4. 选择 创建新组件 选项
  5. 命名为 “修复R2图片URL”(或任何您喜欢的名称)
  6. 在 “Javascript” 选项卡中,粘贴上面的代码
  7. 点击 创建 按钮
  8. 点击 启用 按钮,选择应用到的主题(通常是 “默认”)

验证方法

安装完成后:

  1. 刷新论坛页面
  2. 查看包含图片的帖子
  3. 确认缩略图正常显示
  4. 使用浏览器开发者工具检查图片请求是否都指向CDN域名

但客户端方案是最简单、最快速且风险最低的解决方法,特别适合没有服务器直接访问权限的情况。

结论

这个简单的主题组件可以有效解决Discourse与Cloudflare R2存储集成时出现的图片URL问题,无需服务器变更或复杂配置。虽然它是在客户端修复问题而非解决根本原因,但实现简单、效果立竿见影,是一个理想的解决方案。

如果您的Discourse站点也遇到类似问题,欢迎尝试此方案。

1 Like