Описание проблемы
Недавно мы заметили проблему с отображением изображений на форуме, а именно:
- Миниатюры изображений отображаются некорректно.
- При клике на изображения полноэкранный вариант отображается правильно.
- Инструменты разработчика браузера показывают неправильные 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-адреса на правильные в браузере.
Код компонента темы
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: Интегрируется с API Discourse для обработки различных специальных сценариев.
Шаги по установке
- Войдите в учётную запись администратора Discourse.
- Перейдите в раздел Администрирование > Настройка > Компоненты тем.
- Нажмите кнопку Создать.
- Выберите опцию Создать новый компонент.
- Назовите его «Fix R2 Image URLs» (или любым другим предпочтительным именем).
- На вкладке «Javascript» вставьте код выше.
- Нажмите кнопку Создать.
- Нажмите кнопку Включить и выберите тему, к которой нужно применить компонент (обычно «По умолчанию»).
Проверка
После установки:
- Обновите страницу форума.
- Просмотрите сообщения, содержащие изображения.
- Убедитесь, что миниатюры отображаются правильно.
- С помощью инструментов разработчика браузера проверьте, что все запросы изображений указывают на CDN-домен.
Хотя решение на стороне клиента является самым простым, быстрым и наименее рискованным подходом, особенно когда прямой доступ к серверу ограничен.
Заключение
Этот простой компонент темы эффективно решает проблему URL-адресов изображений при интеграции Discourse с хранилищем Cloudflare R2, не требуя изменений на сервере или сложных настроек. Хотя он исправляет проблему на стороне клиента, а не устраняет коренную причину, его легко внедрить, он даёт немедленный результат и является идеальным решением.
Если ваш сайт Discourse также сталкивается с подобными проблемами, не стесняйтесь попробовать это решение.
