Amazon S3 CORS (Cross-Origin Resource Sharing) и междоменная загрузка шрифтов Firefox

Уже давно существует проблема с тем, что Firefox не загружает шрифт из другого источника, чем текущая веб-страница. Обычно проблема возникает, когда шрифты подаются в CDN.

Различные решения были подняты в других вопросах:

CSS @ font-face не работает с Firefox, но работает с Chrome и IE

С появлением Amazon S3 CORS, есть ли решение, использующее CORS для решения проблемы загрузки шрифтов в Firefox?

редактировать: было бы здорово увидеть пример конфигурации S3 CORS.

edit2: я нашел рабочее решение, фактически не понимая, что он сделал. Если кто-нибудь сможет предоставить более подробные объяснения о конфигах и магии фона, которая происходит в интерпретации конфигурации Amazon, это будет очень цениться, как и в случае с nzifnab, который назначает награду за это.

14 ответов

Решение

Обновление 10 сентября 2014 года:

Вам больше не нужно предпринимать какие-либо действия, описанные ниже, поскольку Cloudfront должным образом поддерживает CORS. См. http://aws.amazon.com/blogs/aws/enhanced-cloudfront-customization/ и этот ответ для получения дополнительной информации: /questions/39937028/amazon-s3-cors-cross-origin-resource-sharing-i-mezhdomennaya-zagruzka-shriftov-firefox/39937031#39937031


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

Мои шрифты размещены на S3, но выходят на облачный фронт.

Я не уверен, почему это работает, я думаю, вероятно, что <AllowedMethod>GET а также <AllowedHeader>Content-* нужно.

Если кто-нибудь, имеющий опыт в настройке Amazon S3 CORS, сможет пролить свет на это, он будет очень признателен.

<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
    <CORSRule>
        <AllowedOrigin>https://mydomain.com</AllowedOrigin>
        <AllowedMethod>GET</AllowedMethod>
        <MaxAgeSeconds>3000</MaxAgeSeconds>
        <AllowedHeader>Content-*</AllowedHeader>
        <AllowedHeader>Host</AllowedHeader>
    </CORSRule>
    <CORSRule>
        <AllowedOrigin>https://*.mydomain.com</AllowedOrigin>
        <AllowedMethod>GET</AllowedMethod>
        <MaxAgeSeconds>3000</MaxAgeSeconds>
        <AllowedHeader>Content-*</AllowedHeader>
        <AllowedHeader>Host</AllowedHeader>
    </CORSRule>
</CORSConfiguration>

редактировать:

Некоторые разработчики сталкиваются с проблемами кэширования Cloudfront Access-Control-Allow-Origin заголовок. Эта проблема была решена сотрудниками AWS по ссылке ( https://forums.aws.amazon.com/thread.jspa?threadID=114646) ниже, которую комментирует @Jeff-Atwood.

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

С помощью curl проверить заголовки ответа:

Домен A: a.domain.com

curl -i -H "Origin: https://a.domain.com" http://hashhashhash.cloudfront.net/font.woff?https_a.domain.com

Заголовки ответа из домена A:

Access-Control-Allow-Origin: https://a.domain.com
Access-Control-Allow-Methods: GET
Access-Control-Max-Age: 3000
Access-Control-Allow-Credentials: true
X-Cache: Miss from Cloudfront

Домен B: b.domain.com

curl -i -H "Origin: http://b.domain.com" http://hashhashhash.cloudfront.net/font.woff?http_b.domain.com

Заголовки ответа из домена B:

Access-Control-Allow-Origin: http://b.domain.com
Access-Control-Allow-Methods: GET
Access-Control-Max-Age: 3000
Access-Control-Allow-Credentials: true
X-Cache: Miss from Cloudfront

Вы заметите Access-Control-Allow-Origin вернул разные значения, которые прошли кеширование Cloudfront.

После некоторой настройки я, кажется, заставил это работать без взлома строки запроса. Более подробная информация здесь: http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/RequestAndResponseBehaviorS3Origin.html

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

Справочная информация: я использую приложение Rails с гемом asset_sync для размещения активов на S3. Это включает в себя шрифты.

В консоли S3 я щелкнул на своем сегменте, свойствах и "редактировании конфигурации cors", здесь: Кнопка конфигурации CORS

Внутри текстовой области у меня есть что-то вроде:

<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
    <CORSRule>
        <AllowedOrigin>https://*.example.com</AllowedOrigin>
        <AllowedMethod>GET</AllowedMethod>
        <MaxAgeSeconds>3000</MaxAgeSeconds>
        <AllowedHeader>*</AllowedHeader>
    </CORSRule>
</CORSConfiguration>

Затем на панели Cloudfront ( https://console.aws.amazon.com/cloudfront/home) я создал дистрибутив, добавил Origin, который указал на мое ведро S3 добавление происхождения

Затем добавлено поведение для пути по умолчанию, указывающее на исходную точку S3, которую я установил. Я также нажал на заголовки белого списка и добавил Origin:добавление поведения и заголовков белого списка

Что происходит сейчас, так это то, что я считаю правильным:

1) Убедитесь, что заголовки S3 установлены правильно

curl -i -H "Origin: https://example.com" https://s3.amazonaws.com/xxxxxxxxx/assets/fonts/my-cool-font.ttf
HTTP/1.1 200 OK
x-amz-id-2: Ay63Qb5uR98ag47SRJ91+YALtc4onRu1JUJgMTU98Es/pzQ3ckmuWhzzbTgDTCt+
x-amz-request-id: F1FFE275C0FBE500
Date: Thu, 14 Aug 2014 09:39:40 GMT
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Methods: GET
Access-Control-Max-Age: 3000
Access-Control-Allow-Credentials: true
Vary: Origin, Access-Control-Request-Headers, Access-Control-Request-Method
Cache-Control: public, must-revalidate, proxy-revalidate, max-age=180
Last-Modified: Mon, 09 Dec 2013 14:29:04 GMT
ETag: "98918ee7f339c7534c34b9f5a448c3e2"
Accept-Ranges: bytes
Content-Type: application/x-font-ttf
Content-Length: 12156
Server: AmazonS3

2) Проверьте, что Cloudfront работает с заголовками

curl -i -H "Origin: https://example.com" https://xxxxx.cloudfront.net/assets/fonts/my-cool-font.ttf
HTTP/1.1 200 OK
Content-Type: application/x-font-ttf
Content-Length: 12156
Connection: keep-alive
Date: Thu, 14 Aug 2014 09:35:26 GMT
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Methods: GET
Access-Control-Max-Age: 3000
Access-Control-Allow-Credentials: true
Cache-Control: public, must-revalidate, proxy-revalidate, max-age=180
Last-Modified: Mon, 09 Dec 2013 14:29:04 GMT
ETag: "98918ee7f339c7534c34b9f5a448c3e2"
Accept-Ranges: bytes
Server: AmazonS3
Vary: Origin
X-Cache: Miss from cloudfront
Via: 1.1 77bdacfea247b6cbe84dffa61da5a554.cloudfront.net (CloudFront)
X-Amz-Cf-Id: cmCxaUcFf3bT48zpPw0Q-vDDza0nZoWm9-_3qY5pJBhj64iTpkgMlg==

(Обратите внимание, что вышеприведенное было пропущено из облачного фронта, потому что эти файлы кэшировались в течение 180 секунд, но то же самое работало и с хитами)

3) Хит облачного фронта с другим источником (но тот, который разрешен в CORS для корзины S3) - Access-Control-Allow-Origin не кешируется! ура!

curl -i -H "Origin: https://www2.example.com" https://xxxxx.cloudfront.net/assets/fonts/my-cool-font.ttf
HTTP/1.1 200 OK
Content-Type: application/x-font-ttf
Content-Length: 12156
Connection: keep-alive
Date: Thu, 14 Aug 2014 10:02:33 GMT
Access-Control-Allow-Origin: https://www2.example.com
Access-Control-Allow-Methods: GET
Access-Control-Max-Age: 3000
Access-Control-Allow-Credentials: true
Cache-Control: public, must-revalidate, proxy-revalidate, max-age=180
Last-Modified: Mon, 09 Dec 2013 14:29:04 GMT
ETag: "98918ee7f339c7534c34b9f5a448c3e2"
Accept-Ranges: bytes
Server: AmazonS3
Vary: Origin
X-Cache: Miss from cloudfront
Via: 1.1 ba7014bad8e9bf2ed075d09443dcc4f1.cloudfront.net (CloudFront)
X-Amz-Cf-Id: vy-UccJ094cjdbdT0tcKuil22XYwWdIECdBZ_5hqoTjr0tNH80NQPg==

Обратите внимание, что домен успешно изменился без взлома строки запроса.

Когда я меняю заголовок Origin, кажется, что X-Cache: Miss from cloudfront по первому запросу потом получаю ожидаемое X-Cache: Hit from cloudfront

PS Стоит отметить, что при выполнении curl -I (заглавная I) НЕ будут отображаться заголовки Access-Control-Allow-Origin, так как это только HEAD, я делаю -i, чтобы сделать его GET и прокрутить вверх.

Мои шрифты обслуживались правильно до последнего нажатия на Heroku... Я не знаю почему, но подстановочный знак в разрешенном источнике CORS перестал работать. Я добавил все свои домены prepro и pro в политику CORS в настройке корзины, так что теперь это выглядит так:

<CORSConfiguration>
    <CORSRule>
        <AllowedOrigin>http://prepro.examle.com</AllowedOrigin>
        <AllowedOrigin>https://prepro.examle.com</AllowedOrigin>
        <AllowedOrigin>http://examle.com</AllowedOrigin>
        <AllowedOrigin>https://examle.com</AllowedOrigin>
        <AllowedMethod>GET</AllowedMethod>
        <MaxAgeSeconds>3000</MaxAgeSeconds>
        <AllowedHeader>Authorization</AllowedHeader>
    </CORSRule>

</CORSConfiguration>

ОБНОВЛЕНИЕ: добавьте свой http://localhost:PORT тоже

В конфигурации Amazon S3 CORS (S3 Bucket / Permissions / CORS), если вы используете это:

<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
    <AllowedOrigin>*</AllowedOrigin>
    <AllowedMethod>GET</AllowedMethod>
    <MaxAgeSeconds>3000</MaxAgeSeconds>
    <AllowedHeader>*</AllowedHeader>
</CORSRule>

CORS хорошо работает для файлов Javascript и CSS, но не работает для файлов шрифтов.

Вы должны указать домен, чтобы разрешить CORS, используя шаблон, выраженный в ответе @VKen: /questions/39937028/amazon-s3-cors-cross-origin-resource-sharing-i-mezhdomennaya-zagruzka-shriftov-firefox/39937031#39937031

Итак, используйте это:

<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
    <AllowedOrigin>*</AllowedOrigin>
    <AllowedMethod>GET</AllowedMethod>
    <MaxAgeSeconds>3000</MaxAgeSeconds>
    <AllowedHeader>*</AllowedHeader>
</CORSRule>
<CORSRule>
    <AllowedOrigin>https://*.mydomain.com</AllowedOrigin>
    <AllowedMethod>GET</AllowedMethod>
    <MaxAgeSeconds>3000</MaxAgeSeconds>
    <AllowedHeader>*</AllowedHeader>
</CORSRule>
</CORSConfiguration>

Не забудьте заменить "mydomain.com" для вашего домена.

После этого аннулируйте кэш CloudFront (CloudFront / Invalidations / Create Invalidation), и он будет работать.

Что ж, в документации говорится, что вы можете прикрепить конфигурацию как "подресурс cors в вашем сегменте". Я решил, что это означает, что я создам файл с именем "cors" в корне моего сегмента конфигурации, но это не сработает. В конце концов мне пришлось войти в администрацию Amazon S3 и добавить конфигурацию в properties диалог моего ведра.

S3 может использовать лучшую документацию...

В моем случае я не определил пространство имен и версию XML в конфигурации CORS. Определение тех, кто работал.

Изменено

<CORSConfiguration>

в

<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">

Есть лучший и простой способ!

Лично я предпочитаю использовать свои субдомены DNS для решения этой проблемы. Если мой CDN находится за cdn.myawesomeapp.com вместо sdf73n7ssa.cloudfront.net, то браузеры не собираются волноваться и блокировать их как проблемы междоменной безопасности.

Чтобы указать свой поддомен в своем домене AWS Cloudfront, перейдите на панель управления AWS Cloudfront, выберите свой дистрибутив Cloudfront и введите свой поддомен CDN в поле Альтернативные имена доменов (CNAMEs). Подойдет что-то вроде cdn.myawesomeapp.com.

Теперь вы можете обратиться к своему провайдеру DNS (например, к AWS Route 53) и создать CNAME для cdn.myawesomeapp.com, указывающий на sdf73n7ssa.cloudfront.net.

http://blog.cloud66.com/cross-origin-resource-sharing-cors-blocked-for-cloudfront-in-rails/

Эта конфигурация работала для меня. I can list object, retrieve, update and delete.

<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
  <CORSRule>
    <AllowedOrigin>http://localhost:3000</AllowedOrigin>
    <AllowedMethod>HEAD</AllowedMethod>
    <AllowedMethod>GET</AllowedMethod>
    <AllowedMethod>PUT</AllowedMethod>
    <AllowedMethod>POST</AllowedMethod>
    <AllowedMethod>DELETE</AllowedMethod>
    <AllowedHeader>*</AllowedHeader>
    <ExposeHeader>ETag</ExposeHeader>
    <ExposeHeader>x-amz-meta-custom-header</ExposeHeader>
  </CORSRule>
</CORSConfiguration>

Решение 2021 г., не рискуя безопасностью, позволяя "*" в AllowedDomains.

Шаг 1) Разрешите S3 использовать CORS

В сегменте S3 > Разрешения> Совместное использование ресурсов между разными источниками (CORS) добавьте список вашего домена / доменов в AllowedOrigins. Примеры см. В официальном документе . Вам нужно только GET для AllowedMethods.

Шаг 2) Сообщите CloudFront об отправке заголовков CORS

Убедитесь, что в вашем CloudFront Behavior <Origin Request Policy вы выбрали политику, которая отправляет origin а также access-control-request-headers заголовки, например Managed-CORS-S3Origin.

Шаг 3) [Необязательно, только если у вас более одного домена]

Посмотрите этот мой ответ о том, как обрабатывать несколько доменов в CORS для S3+CloudFront.

Шаг 4) Аннулируйте свое распространение CloudFront

Удачи!

<ifModule mod_headers.c>

   Header set Access-Control-Allow-Origin: http://domainurl.com

</ifModule>

Простое решение

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

Если вы находитесь в сценарии "Я сделал все, что они сказали, но он все равно не работает", вероятно, это проблема, связанная с кешем в Chrome и Safari. Предположим, у вашего сервера есть правильный набор конфигурации CORS:

<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
    <CORSRule>
        <AllowedOrigin>*</AllowedOrigin>
        <AllowedMethod>GET</AllowedMethod>
        <MaxAgeSeconds>3000</MaxAgeSeconds>
    </CORSRule>
</CORSConfiguration>

а в Firefox все работает нормально, а в Chrome и Safari - нет. Если доступ к удаленному пути изображения от обоих в простой<img src="http://my.remote.server.com/images/cat.png"> и из элемента src js Image, как показано ниже:

var myImg = new Image()
myImg.crossOrigin = 'Anonymous'
myImg.onload = () => {
  // do stuff (maybe draw the downloaded img on a canvas)
}
myImg.src = 'http://my.remote.server.com/images/cat.png'

Вы можете получить No 'Access-Control-Allow-Origin'ошибка в Chrome и Safari. Это произошло потому, что первый<img>каким-то образом портит кеш браузера, и когда вы позже пытаетесь получить доступ к тому же изображению (в элементе изображения в коде), оно просто ломается. Чтобы избежать этого, вы можете добавить фиктивный параметр GET к одному пути.src, чтобы заставить браузер повторно запрашивать изображение и избегать использования кеша, например:

<img src="http://my.remote.server.com/images/cat.png?nocache=true"></img>

Перезапуск моего весеннего загрузочного приложения (сервера) решил проблему для меня.

Я правильно настроил CORS на S3. Завиток давал правильный ответ с заголовком источника. Safari правильно выбирал шрифт. Это был только хром, который не был готов принять CORS.

Не уверен, что именно вызвало поведение. Должно быть что-то делать с If-Modified-Since

Да, конечно. Firefox поддерживает CORS для шрифтов, как требует спецификация на http://dev.w3.org/csswg/css3-fonts/

Я испытал ту же проблему. Мне не нужно было добавлять CNAME в мой CDD, чтобы избежать междоменных проблем... Мне просто нужно было сделать следующее:

Перейдите в свойства вашего Bucket -> Разрешения -> Добавить дополнительные разрешения -> Получатель: Все и отметьте опцию "Список".

Это графический пример.

Надеюсь, что в полной мере это будет полезно для кого-то.

Другие вопросы по тегам