問題の説明
フォーラムでの画像表示に問題があることが最近確認されました。具体的には以下の通りです。
- 画像のサムネイルが正しく表示されない。
- 画像をクリックすると、フルサイズの画像は正しく表示される。
- ブラウザの開発者ツールで、画像URLが正しくないことが示される。
調査の結果、根本原因は画像URLのドメイン名が間違っていることでした。
- 正しいURL:
https://store.starorigin.cc/optimized/1X/[imageID].jpeg - 間違ったURL:
https://info.7a4081a2d83d3f43fe6b1be1c926fd1c.r2.cloudflarestorage.com/optimized/1X/[imageID].jpeg
システムは、設定されたCDNドメインではなく、生のR2バケットの誤ったドメインを使用しています。
技術的分析
これは、DiscourseがCloudflare R2に保存された画像を処理する際に発生する既知の問題です。場合によっては、s3_cdn_urlが設定されていても、Discourseは最適化された画像(サムネイルなど)を生成する際に、CDN URLではなく生のストレージURLを使用することがあります。
これは以下の要因に関連している可能性があります。
- Discourseのバージョン
- S3互換ストレージの設定
OptimizedImageテーブルでのURLの保存方法
ソリューション
最もシンプルで効果的な解決策は、クライアントサイドでの修正のためにDiscourseテーマコンポーネントを使用することです。これにはデータベース操作やサーバー設定の変更は必要ありません。ブラウザで間違ったURLを正しいURLに自動的に置き換える短いJavaScriptコードスニペットを追加するだけです。
テーマコンポーネントコード
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サイトでも同様の問題が発生している場合は、このソリューションを試してみてください。
