Проблема с загрузкой веб-шрифтов при обслуживании из AWS Cloudfront

Итак, вот моя головоломка! Я пытался заставить Cloudfront нормально работать с моим сервером nginx в течение последних трех дней ... прочитал бесчисленное количество сообщений и статей в блогах StackOverflow ... просмотрел межсайтовые сети, и я все еще застрял с проблемами, связанными с политиками междоменного доступа, когда речь идет о шрифтах, обслуживающих Cloudfront. Я собираюсь опубликовать свою полную настройку в надежде, что кто-то с большим опытом поможет мне разобраться в том, что происходит. Я надеюсь, что в будущем этот пост будет полезен многим другим, сталкивающимся с подобными проблемами. Поехали ...

Конфигурация Nginx:

У меня есть веб-сервер nginx со следующей конфигурацией серверного блока. (... усечено для краткости)

    server {
        server_name  example.com www.example.com;
        root /var/www/example.com/html;
        index index.html index.htm;

        location / {
            try_files $uri $uri/ =404;
        }
        location /assets {
            autoindex on;
        }

        # Media
        location ~* \.(jpe?g|gif|png|ico|cur|gz|svgz?|mp4|ogg|ogv|webm|htc|webp)$ {
            expires 1M;
            access_log off;
            add_header Cache-Control public;
        }

        # Fonts
        location ~* \.(eot|ttf|woff|woff2|svg)$ {
            expires 365d;
            access_log off;
            add_header Cache-Control public;
            add_header Access-Control-Allow-Origin example.com;
            // Have also tried setting the "Access-Control-Allow-Origin" header to "*", but I'd prefer not to do this for security reasons.
        }

    }

К вашему сведению: все файлы моего веб-сайта, которые я хотел бы обслуживать и выгружать в CloudFront, находятся в /assets каталоге моего виртуального хоста. (т. е. http://example.com/assets/..)


CloudFront:

Я создал новый дистрибутив CloudFront со следующими настройками:

Примечание. Я не использую S3 для размещения файлов и ресурсов своего веб-сайта.

Общий:

  • Альтернативные доменные имена (CNAME): static.example.com
  • Корневой объект по умолчанию: index.html

Происхождение:

  • Имя исходного домена: example.com
  • Исходный путь: (оставлено пустым)
  • Исходные протоколы SSL: TLSv1.2, TLSv1.1, TLSv1
  • Политика исходного протокола: только HTTP
  • Порт HTTP: 80
  • Порт HTTPS: 443
  • Пользовательские заголовки источника: (нет)

Поведение:

  • Шаблон пути: По умолчанию () *
  • Политика протокола средства просмотра: HTTP и HTTPS
  • Разрешенные методы HTTP: GET, HEAD
  • Кэшированные методы HTTP: GET, HEAD (по умолчанию кешируется)
  • Forward Headers: Whitelist
    • Access-Control-Allow-Origin
  • Кэширование объектов: Использовать заголовки исходного кэша
  • Строки прямого запроса: Нет (улучшает кеширование)
  • Автоматическое сжатие объектов: Да

Настройки DNS:

Часть моего файла зоны ...

example.com. 1800 IN A 12.34.567.890  //faked IP here for privacy reasons
www.example.com. 1800 IN CNAME example.com.
static.example.com. 1800 IN CNAME kg72kgf83nhfy3.cloudfront.net.  //faked CloudFront dist. domain name here for privacy reasons

Что происходит? Почему это не работает?

Итак, CloudFront выполняет свою работу по обработке и развертыванию моего дистрибутива, и я предполагаю, что ресурсы будут извлечены из моего веб-каталога '/ assets / ..'. Все ссылки src, href и CSS url() указывают на http://static.example.com в моих текущих документах HTML и CSS, включая все font-face ссылки. После развертывания дистрибутива я попал на свой сайт http://example.com в браузере.

Похоже, что все статические ресурсы сайта правильно обслуживаются CloudFront с соответствующими заголовками кэширования, как определено в моей конфигурации nginx ... ИСКЛЮЧАЯ ... веб-шрифтов. Я получаю отсутствующие шрифты на странице и сообщения об ошибках политики междоменного доступа в консоли браузера.

Заголовки—

  • Изображение для справки (при проверке связи с моим сервером):

    curl -I "http://example.com/assets/images/image1.png"
    HTTP/1.1 200 OK
    Server: nginx/1.6.3
    Date: Sun, 15 May 2016 02:09:25 GMT
    Content-Type: image/png
    Content-Length: 194665
    Last-Modified: Sun, 15 May 2016 01:52:35 GMT
    Connection: keep-alive
    ETag: "5737d663-2f869"
    Expires: Tue, 14 Jun 2016 02:09:25 GMT
    Cache-Control: max-age=2592000
    Cache-Control: public
    Accept-Ranges: bytes
    
  • Шрифт (при пинге моего сервера):

    curl -I "http://example.com/assets/fonts/webfont.woff"
    HTTP/1.1 200 OK
    Server: nginx/1.6.3
    Date: Sun, 15 May 2016 02:10:29 GMT
    Content-Type: application/font-woff
    Content-Length: 8752
    Last-Modified: Sun, 15 May 2016 01:51:55 GMT
    Connection: keep-alive
    Vary: Accept-Encoding
    ETag: "5737d63b-2230"
    Expires: Mon, 15 May 2017 02:10:29 GMT
    Cache-Control: max-age=31536000
    Cache-Control: public
    Access-Control-Allow-Origin: example.com
    Accept-Ranges: bytes
    
  • То же изображение (при запросе из CloudFront):

    curl -I "http://static.example.com/assets/images/image1.png"
    HTTP/1.1 200 OK
    Content-Type: image/png
    Content-Length: 194665
    Connection: keep-alive
    Server: nginx/1.6.3
    Date: Sun, 15 May 2016 02:39:16 GMT
    Last-Modified: Sun, 15 May 2016 01:52:35 GMT
    ETag: "5737d663-2f869"
    Expires: Tue, 14 Jun 2016 02:39:16 GMT
    Cache-Control: max-age=2592000
    Cache-Control: public
    Accept-Ranges: bytes
    X-Cache: Miss from cloudfront
    Via: 1.1 lots_of_random_characters_i_dont_know_if_should_share_here.cloudfront.net (CloudFront)
    X-Amz-Cf-Id: lSM1plINYENbYycBn424LJ2wdtDhS3CpqAFiDSoxQDEctP_WM09bUQ==
    
  • Тот же шрифт (при запросе из CloudFront):

    curl -I "http://static.example.com/assets/fonts/webfont.woff"
    HTTP/1.1 200 OK
    Content-Type: application/font-woff
    Content-Length: 8752
    Connection: keep-alive
    Server: nginx/1.6.3
    Date: Sun, 15 May 2016 02:41:00 GMT
    Last-Modified: Sun, 15 May 2016 01:51:55 GMT
    ETag: "5737d63b-2230"
    Expires: Mon, 15 May 2017 02:41:00 GMT
    Cache-Control: max-age=31536000
    Cache-Control: public
    Access-Control-Allow-Origin: example.com
    Accept-Ranges: bytes
    Vary: Accept-Encoding
    X-Cache: Miss from cloudfront
    Via: 1.1 lots_of_random_characters_i_dont_know_if_should_share_here.cloudfront.net (CloudFront)
    X-Amz-Cf-Id: vNfiyurS8pjosofnpLNSrnZuaGFg0V4xIs4ySCm05NKDMZ_PozhuOg==
    

Загрузка моего веб-сайта на http://example.com, все похоже, работает (т.е. изображения) ИСКЛЮЧАЯ веб-шрифты. При проверке консоли браузера для каждого шрифта выводится следующее сообщение:

Шрифт из источника "http://static.example.com" заблокирован для загрузки перекрестным Политика общего доступа к исходным ресурсам: заголовок Access-Control-Allow-Origin содержит недопустимое значение example.com. Следовательно, к источнику "http://example.com" не разрешен доступ.

Итак, у кого-нибудь есть мысли ?? Я был бы очень признателен за помощь / ввод. Я молодой веб-разработчик, просто пытаюсь учиться.

Спасибо! :)
–Кайл



Сноски:

  • Одно из многих сообщений в блоге, за которыми я следил, но не смог заставить вещи работать.
  • Я планирую добавлять хешированные строки запроса в конец каждого файла (например, //static.example.com/assets/images/image.png?622c6911), чтобы сделать кеш CloudFront недействительным. Таким образом, мне не нужно всегда повторно загружать новые ресурсы с изменяющимися именами ... Я могу просто управлять аннулированием из HTML и добавлять новую строку запроса к ресурсам, когда я хочу, чтобы CloudFront запрашивал последнюю версию этого файла с моего веб-сервера. Источник.
  • В конечном итоге я куплю SSL-сертификат для своего сайта, поэтому я хотел бы, чтобы трафик поддерживал запросы HTTP и HTTPS.

person kaffolder    schedule 15.05.2016    source источник


Ответы (1)


Объяснение здесь:

Заголовок Access-Control-Allow-Origin содержит недопустимое значение example.com. Следовательно, к источнику "http://example.com" не разрешен доступ.

Происхождение _1 _... не example.com. Заголовок вашего ответа имеет неправильное значение. По определению, источником является схема + имя хоста + порт (при этом неявные порты 80 и 443 опущены для http и https на стандартных портах).

Когда запрос не подчиняется правилам перекрестного происхождения, например, в случае с изображениями, эта неправильная конфигурация на вашем веб-сервере игнорируется браузером. Что касается шрифтов, вы попадаете в эту стену, потому что значение искажено.

add_header Access-Control-Allow-Origin example.com;

Это корень вашей проблемы. Вам необходимо ответить тем же источником, который был отправлен браузером в заголовке Origin:, при условии, что источник действительно действителен и должен быть разрешен. Я не специалист по nginx, согласно этому ответу, вы можете проверить входящее происхождение с помощью регулярного выражения и установить ответ соответственно:

if ($http_origin ~* "^https?://.*example\.com$" ) {
    add_header Access-Control-Allow-Origin $http_origin;
}

Я не знаком с причудами регулярных выражений nginx, но я немного снисходительный, но идею вы поняли.

Прежде чем это сработает, нам нужно исправить поведение кеша CloudFront.

Перенаправляемые заголовки: белый список

Доступ-Контроль-Разрешить-Происхождение

Это не заголовок запроса ... это заголовок ответа, поэтому его добавление в белый список на самом деле ничего не делает.

Вместо этого вам нужно будет внести заголовок Origin в белый список, чтобы он был перенаправлен на веб-сервер с помощью CloudFront, чтобы сервер мог ответить тем же значением в Access-Control-Allow-Origin:, как показано выше.

Access-Control-Request-Headers и Access-Control-Request-Method, вероятно, также должны быть внесены в белый список, хотя для GET запросов я не уверен, что они будут иметь значение.

Вам также, вероятно, следует изменить разрешенные методы, чтобы включить OPTIONS в дополнение к GET и HEAD.


Бонусный материал:

Я планирую добавлять хешированные строки запроса в конец каждого файла (например, //static.example.com/assets/images/image.png?622c6911), чтобы сделать кеш CloudFront недействительным.

В этом случае вам нужно установить Forward Query Strings на Yes.

CloudFront кэширует объекты на основе того, что фактически отправляет на сервер. Добавление строки запроса сделает недействительным только кеш браузера, но не кеш CloudFront, если строки запроса не будут переадресованы источнику. Да, вам нужно включить это, даже если вашему серверу не нужны или не нужны строки запроса, если строки запроса предназначены для использования для очистки кеша CloudFront. Вот почему их не пересылка «улучшает кеширование». CloudFront будет «улучшать» его, полностью игнорируя их при определении, есть ли уже кэшированная версия объекта.

Также обратите внимание, что заголовок Via не содержит конфиденциальной информации, как и X-Amz-Cf-Id.

person Michael - sqlbot    schedule 15.05.2016
comment
ВАУ! Большое спасибо SOOO за ваш обстоятельный и хорошо информированный ответ. Сегодня днем ​​мне удалось отключить и удалить существующий дистрибутив CloudFront и, следуя вашим инструкциям, настроить новый. Примерно через полчаса после того, как файлы были распространены и изменения DNS распространены, все работает ОТЛИЧНО !! Спасибо, что приложили все усилия, чтобы не только дать правильный ответ, но и подробно объяснить каждый шаг, чтобы я мог продолжить свое обучение. Ты жжешь! :) - person kaffolder; 16.05.2016