问题描述
我们最近注意到论坛上的图片显示存在一个问题,具体表现为:
- 图片缩略图未正确显示。
- 点击图片可以正确显示全尺寸图片。
- 浏览器开发者工具显示错误的图片 URL。
经过排查,根本原因是图片 URL 中的域名不正确:
- 正确 URL:
https://store.starorigin.cc/optimized/1X/[imageID].jpeg - 错误 URL:
https://info.7a4081a2d83d3f43fe6b1be1c926fd1c.r2.cloudflarestorage.com/optimized/1X/[imageID].jpeg
系统正在使用原始 R2 存储桶的错误域名,而不是我们配置的 CDN 域名。
技术分析
这是 Discourse 在处理存储在 Cloudflare R2 中的图片时的一个已知问题。在某些情况下,即使配置了 s3_cdn_url,Discourse 在生成优化图片(如缩略图)时仍可能使用原始存储 URL 而不是 CDN URL。
这可能与以下因素有关:
- Discourse 版本
- S3 兼容存储的配置
- URL 在
OptimizedImage表中的存储方式
解决方案
最简单有效的解决方案是使用 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']
});
}
});
代码工作原理
此代码执行以下操作:
- 全面检测: 查找包含错误域名的所有图片 URL。
- 多元素处理: 处理各种图片元素和属性(img 标签、延迟加载图片、背景图片等)。
- 动态监控: 使用
MutationObserver监控页面更改,确保动态加载的内容也得到修复。 - Discourse 集成: 与 Discourse API 集成,以处理各种特殊场景。
安装步骤
- 登录您的 Discourse 管理员帐户。
- 转到 Admin > Customize > Theme Components。
- 点击 New 按钮。
- 选择 Create new component 选项。
- 将其命名为“Fix R2 Image URLs”(或您喜欢的任何名称)。
- 在“Javascript”选项卡中,粘贴上面的代码。
- 点击 Create 按钮。
- 点击 Enable 按钮,然后选择要应用的主题(通常是“Default”)。
验证
安装后:
- 刷新论坛页面。
- 查看包含图片的帖子。
- 确认缩略图已正确显示。
- 使用浏览器的开发者工具检查图片请求是否都指向 CDN 域名。
客户端解决方案是最简单、最快捷、风险最低的方法,尤其是在服务器访问受限的情况下。
结论
这个简单的主题组件有效地解决了 Discourse 与 Cloudflare R2 存储集成时的图片 URL 问题,无需进行服务器更改或复杂的配置。虽然它是在客户端修复问题,而不是解决根本原因,但它易于实现,可立即看到效果,并且是一个理想的解决方案。
如果您的 Discourse 站点也遇到类似问题,请随时尝试此解决方案。
