Недавно я добавил атрибут crossorigin к определенным тегам сценария, чтобы позволить моим скриптам собирать информацию об ошибках из сценариев из другого поддомена. Я добавил заголовок в nginx, чтобы разрешить запрос перекрестного происхождения.
С тех пор я иногда загружаю страницу без браузера, запрашивающего определенные файлы javascript с сервера. Перезагрузка страницы разрешает проблему, но это произошло несколько раз.
Я думаю, что это связано с CORS, но поскольку он работает большую часть времени, я не знаю, как его воспроизвести.
Вот некоторые отрывки из моего кода:
Конфигурация Nginx содержит это правило для файлов javascript в определенном месте:
add_header 'Access-Control-Allow-Origin' "$http_origin";
Мой тег скрипта на странице php:
<script type="text/javascript" src="<?php print "$host/js/$filename?v=$version";?>" crossorigin></script>
Когда моя страница загружается, я вижу в Firebug, что тег скрипта верен, но на вкладке Firebug Net нет даже показанного запроса. Обычно отображается запрос, даже если он использует кешированную версию файла.
Я нашел здесь один вопрос, который, как я думал, может быть связан: все мои браузеры не отправляют исходный заголовок. Но, думая об этом дальше, я думаю, что должен быть начальный запрос, который потерпит неудачу и который будет отображаться в Firebug.
У кого-нибудь есть теории о том, почему это может произойти?
Изменить: я добавил отдельный журнал доступа для своих запросов CORS. Любой файл в местоположении, который получает Nginx, добавляющий заголовок CORS, также регистрируется в новом журнале доступа.
Когда страница не загружает файл javascript, Nginx регистрирует запрос с 304 статусом (не изменен). Это означает, что Nginx получил условный запрос на ресурс, только если он был изменен, а Nginx отправил обратно 304 и ничего больше. Если кешированная версия не была загружена заголовком CORS, возможно, javascript не может быть выполнен.
У меня есть номер версии, который я добавляю к src тега скрипта, как показано выше. Номер этой версии изменился. Разве это не должно заставлять браузер повторно запрашивать все эти ресурсы, как если бы у них было другое имя файла? Я думаю, что браузер должен был рассматривать их как нераскрытые ресурсы. Там не должно было быть никаких запросов, которые могут привести к 304. Что может быть причиной этого?
Вам нужны Vary: Origin в заголовках ответов.
Я понял, что вызывает это. Во-первых, нам нужна дополнительная информация о конфигурации.
У меня 3 хоста, a.my.com, b.my.com и c.my.com. Статические файлы обслуживаются с сайта c.my.com, а html и php подаются с сайта.my.com и b.my.com.
Я добавил атрибут crossorigin к своим тегам сценария, чтобы я мог получать полезную информацию об ошибках из своих сценариев. См. Вопрос SO, описывающий эту проблему здесь: Cryptic «Ошибка скрипта». сообщается в Javascript в Chrome и Firefox
Я использую запрашивающий хост как разрешенное происхождение, а не *, как предшественник для whitelist разрешенных источников. См. Этот вопрос для получения дополнительной информации. Как правильно настроить nginx Access-Control-Allow-Origin в заголовок ответа на основе заголовка Origin из запроса?
Моя конфигурация nginx имеет длительный срок действия для статического контента, поэтому материал кэшируется и не загружает мой сервер с повторными запросами. Я добавляю номер версии в url для статического контента, чтобы его можно было запросить повторно, когда что-то изменилось. Номер версии исходит из моей версии в svn, поэтому, когда я обновляю файлы сервера до последней версии, браузеры все начнут загружать новый URL-адрес для каждого статического файла.
Итак, вот что происходит:
Новый пользователь посещает a.my.com и загружает страницу. Файлы javascript с 1 по 5 загружаются с сайта c.my.com для использования на сайте. Nginx отправляет их с заголовком источника, разрешающим «a.my.com» и датой будущего истечения срока. Эта страница отлично работает, и javascript загружается успешно.
Затем пользователь переходит к другой части сайта на сайте b.my.com и загружает страницу. Файлы javascript с 1 по 10 запрашиваются с сайта c.my.com. Файлы с 1 по 5 – это те же файлы, которые были загружены для a.my.com. Браузер знает, что у него есть эти файлы в кеше, поэтому он запрашивает nginx для своего статуса. Nginx отвечает с 304 (не изменен), и браузер продолжает запрашивать следующий файл.
Итак, теперь браузер загрузил файлы с 6 по 10 с сайта c.my.com и посмотрел в кеш для файлов с 1 по 5. Кэш-файлы имеют свой заголовок заголовка источника, и это говорит, что «a.my.com» разрешенное происхождение. Страница, запрашивающая файлы, находится на b.my.com, поэтому она не соответствует и не разрешается использовать их. Таким образом, он молча отбрасывает их и показывает пользователю страницу с отсутствующим javascript.
Решения:
Одним из решений является отправка Access-Control-Allow-Origin со значением *, чтобы разрешить любое происхождение. Это означало бы, что кешированный файл разрешен для текущего источника, даже если он не инициировал первую загрузку. Для этого есть последствия для безопасности, о чем говорится в этом вопросе SO: когда безопасно включить CORS?
Второе решение состоит в том, чтобы каждый источник использовал другой URL для одного и того же статического файла. Это заставляет браузер кэшировать их отдельно. Это позволяет заголовку Access-Control-Allow-Origin быть конкретным для одного источника. Стоимость больше запросов ресурсов, поступающих на сервер, а браузер пользователя использует больше памяти и хранилища для кэшированных ресурсов.