CDN загрузил страницу не полностью: ищем CSS, JS и изображения

Страница открывается, но выглядит сломанной: нет стилей, не работает JavaScript или пропали изображения. Ищем конкретные запросы и отделяем ошибку сборки от кэша CDN.

Когда CDN загружает страницу не полностью, сама HTML-страница часто приходит успешно, а один или несколько зависимых ресурсов — CSS, JavaScript, шрифт или изображение — не загружаются либо блокируются браузером. Поэтому начинать нужно не с общего вопроса «работает ли CDN», а с поиска первого конкретного ресурса, который нарушил загрузку страницы.

Полезный результат диагностики выглядит так: точный URL ресурса, инициатор запроса, код ответа или текст блокировки, заголовки, версия файла и различие между ответами через CDN и напрямую с origin. Этого достаточно, чтобы выбрать исправление, не очищая весь кэш наугад.

Сначала зафиксируйте симптом

Откройте страницу в приватном окне, затем инструменты разработчика. На вкладке Network включите Disable cache и перезагрузите страницу. Не ограничивайтесь фильтром Fetch/XHR: переключайтесь между CSS, JS, Img, Font или используйте общий список.

Для каждого подозрительного запроса зафиксируйте:

  • полный URL, включая домен, путь и query string;
  • тип ресурса и столбец Initiator;
  • HTTP-код либо пометку браузера о блокировке;
  • Content-Type, размер ответа и его начало во вкладке Response;
  • заголовки кэширования, Age, ETag или Last-Modified, если они есть;
  • время проверки и, если CDN его предоставляет, идентификатор запроса.

Сохраните HAR только если он нужен для совместного разбора, и перед передачей удалите cookies, токены и персональные параметры. Для первичной диагностики обычно достаточно записать данные нескольких сломанных запросов.

Найдите первый сломанный ресурс в Network

Красные строки помогают, но не все ошибки выглядят как 404 или 500.

404 или 410: HTML ссылается на отсутствующую версию

Проверьте, существует ли точный путь на origin и на edge. Типичный сценарий: новый HTML уже содержит /assets/app.9f31.js, а этот файл не был загружен в хранилище, удалён слишком рано или недоступен выбранному CDN-маршруту.

Не подменяйте отсутствующий версионированный файл другой сборкой под тем же именем. Безопаснее вернуть нужный артефакт либо выпустить HTML, который ссылается на реально опубликованную версию.

200, но в ответе HTML вместо CSS или JS

Откройте Headers и Response. Если запрос app.css получил Content-Type: text/html, страницу входа или шаблон ошибки, браузер может отказаться применять ресурс. Причиной бывает fallback-маршрут приложения, правило переписывания URL, авторизация или CDN, который закэшировал ошибочную HTML-страницу как обычный ответ.

Проверяйте не только статус, но и соответствие тела ожидаемому типу ресурса.

403: правило доступа, подпись URL или защита

Сравните запрос из браузера с рабочим запросом: hostname, путь, query string, срок подписанной ссылки, Origin и Referer. Не отключайте защиту целиком. Сначала определите правило, которое отклонило именно этот ресурс.

Запроса вообще нет

Если файла нет в Network, найдите элемент или импорт, который должен был его инициировать. Причина может быть в ошибке JavaScript до динамической загрузки, неверном src/href, условном рендеринге, srcset, ленивой загрузке или в том, что браузер заблокировал адрес ещё до сетевого запроса. Здесь особенно важна вкладка Console.

Прочитайте Console: ответ мог прийти, но браузер его не использовал

CORS

CORS регулирует доступ к ответам между разными origin. Ошибка особенно заметна для fetch, модульных скриптов и шрифтов. В Console обычно указаны исходный origin и отсутствующий либо неподходящий заголовок.

Сверьте Access-Control-Allow-Origin с реальным origin страницы. Если ответ зависит от заголовка Origin, проверьте, входит ли он в cache key или корректно ли используется Vary: Origin. Иначе CDN может раздать одному сайту вариант ответа, сформированный для другого origin.

Не лечите проблему безусловным Access-Control-Allow-Origin: *, если ресурс использует credentials или не должен быть общедоступным. Политика должна соответствовать назначению ресурса.

Content Security Policy

CSP может запретить загрузку с нового CDN-домена, даже если ресурс отвечает 200. Сообщение в Console показывает нарушенную директиву: например, script-src, style-src, img-src или font-src.

Добавляйте в политику только необходимый источник. Не заменяйте точечное правило широкими разрешениями вроде * или unsafe-inline, не оценив последствия. Если используется nonce или hash для скриптов и стилей, проверьте, соответствует ли он текущему HTML.

Mixed content

HTTPS-страница не должна зависеть от ресурсов по http://. Браузер может заблокировать такой запрос или попытаться повысить схему, после чего адрес всё равно не откроется. Исправьте URL в HTML, CSS, манифесте или данных приложения на HTTPS; отключать защиту в браузере — не исправление.

MIME type и модульные скрипты

Для стилей и JavaScript важен корректный Content-Type. Если CDN изменил метаданные объекта или origin отдал fallback HTML, Console укажет на MIME type. Для ES modules требования к загрузке строже, а CORS применяется даже там, где обычный классический скрипт раньше работал.

Проверьте согласованность HTML и версионированных ресурсов

Частая причина неполной страницы — рассинхронизация релиза:

  1. edge уже отдаёт новый HTML;
  2. часть edge-узлов ещё не видит новые файлы или получила отрицательный кэш;
  3. старые файлы удалены до истечения срока жизни старого HTML;
  4. service worker или браузерный кэш продолжает смешивать версии.

Составьте для проблемной страницы небольшой манифест: URL HTML и точные URL критичных CSS/JS. Убедитесь, что каждый файл опубликован до переключения HTML и остаётся доступным, пока старый HTML ещё может встречаться в кэшах и открытых вкладках.

Версионированным файлам подходят уникальные имена, например app.<hash>.js, и длительное кэширование при неизменяемом содержимом. HTML обычно требует другой политики: он должен достаточно быстро получать новые ссылки на сборку. Не перезаписывайте содержимое под тем же «вечным» URL — разные кэши смогут хранить разные варианты без очевидного способа отличить их.

Проверьте cache key до purge

Два визуально одинаковых запроса могут попадать в разные объекты кэша из-за hostname, query string, заголовков, cookies или параметра Origin. И наоборот, ошибочно узкий cache key может склеить ответы, которые должны различаться.

Для сломанного URL сравните:

  • URL из HTML и фактический URL в Network;
  • запрос с query string и без него;
  • варианты с разными Origin, если CORS-ответ динамический;
  • заголовки Age, ETag, Last-Modified и поставщико-зависимый статус кэша;
  • поведение в приватном окне и из другой сети.

Purge имеет смысл только после понимания, какой ключ содержит неправильный объект и почему он туда попал. Иначе очистка временно скроет дефект, а следующий запрос снова закэширует ошибочный ответ. Предпочитайте точечную очистку конкретных URL или версии; глобальный purge увеличивает нагрузку на origin и усложняет наблюдение.

Сравните origin и edge одним и тем же запросом

Цель сравнения — понять, где появляется различие.

  1. Возьмите точный URL пропавшего ресурса из Network.
  2. Получите ответ через публичный CDN-домен и сохраните статус, заголовки и тело либо хеш файла.
  3. Запросите тот же путь у origin разрешённым для вашей инфраструктуры способом, сохранив правильный Host и SNI.
  4. Сравните код, Content-Type, длину или хеш, а также заголовки кэширования.

Если origin уже отдаёт неверный файл, purge CDN не поможет: исправлять нужно публикацию, маршрутизацию или приложение. Если origin корректен, а edge возвращает старую версию, HTML-ошибку или другой тип, исследуйте cache key, TTL, правила преобразования и историю purge. Если ответы корректны оба, возвращайтесь к Console: ресурс может блокироваться политикой браузера или ломаться при выполнении.

Не открывайте origin публично ради теста и не обходите штатную авторизацию. Используйте предусмотренный служебный доступ, журналы или диагностическую точку внутри доверенной сети.

Отдельно исключите service worker и локальный кэш

Флажок Disable cache в DevTools не всегда объясняет поведение service worker. На вкладке Application проверьте, контролирует ли он страницу, какие Cache Storage используются и какой ответ перехватывается. Для проверки можно временно обойти или остановить service worker в инструментах разработчика, не удаляя production-регистрацию у всех пользователей.

Если после обхода страница собирается правильно, исправляйте стратегию обновления service worker и совместимость старого HTML с новыми ресурсами. Простой purge CDN не очищает кэши, уже сохранённые в браузерах.

Порядок диагностики без лишних действий

  1. В Network найдите первый отсутствующий или неверный CSS, JS, шрифт либо изображение.
  2. Запишите точный URL, инициатор, статус, тип ответа и кэш-заголовки.
  3. В Console определите, не блокирует ли ресурс CORS, CSP, mixed content или MIME policy.
  4. Проверьте, совпадают ли версии HTML и файлов сборки.
  5. Сверьте cache key и только затем решайте, нужен ли точечный purge.
  6. Сравните один и тот же ресурс на origin и edge.
  7. Если сеть и CDN корректны, проверьте service worker, локальный кэш и ошибку выполнения JavaScript.

Когда проблема проявляется не постоянно или только у части пользователей, ручного снимка недостаточно. Добавьте в Web-Puls проверку страницы и её критичных публичных ресурсов: это поможет зафиксировать время и внешний симптом, а подробности Network, Console и origin-логов останутся основой точной диагностики.

Источники

Проверьте свой сайт прямо сейчас

Введите адрес сайта: Web-Puls покажет HTTP-код, время ответа и базовую диагностику. Для постоянного контроля можно подключить мониторинг.

Хотите видеть такую историю по своему сайту?

Добавьте сайт в Web-Puls: мы будем проверять доступность, SSL и содержимое страницы.