Завантаження шрифтів міждоменних ресурсів Amazon S3 CORS (міжпоширений розподіл ресурсів) та Firefox


134

Існує давня проблема, коли Firefox не завантажує шрифт іншого походження, ніж поточна веб-сторінка. Зазвичай проблема виникає, коли шрифти подаються на CDN.

В інших питаннях були розглянуті різні рішення:

CSS @ font-face не працює з Firefox, але працює з Chrome та IE

З впровадженням Amazon S3 CORS, чи існує рішення за допомогою CORS для вирішення проблеми завантаження шрифту у Firefox?

редагувати: Було б чудово побачити зразок конфігурації S3 CORS.

edit2: Я знайшов робоче рішення, не розуміючи, що він зробив. Якщо хтось міг би надати більш детальні пояснення щодо конфігурацій та фонової магії, які трапляються в інтерпретації конфігурації Amazon, це буде дуже вдячно, як і у nzifnab, який виставив за це суму.

Відповіді:


148

Оновлення 10 вересня 2014 року:

Вам більше не потрібно робити жодних з рядків запитів нижче, оскільки Cloudfront належним чином підтримує CORS зараз. Дивіться http://aws.amazon.com/blogs/aws/enhanced-cloudfront-customization/ та цю відповідь для отримання додаткової інформації: https://stackoverflow.com/a/25305915/308315


Гаразд, я нарешті змусив шрифти, що працюють за допомогою конфігурації нижче, трохи підкоригуючи приклади документації.

Мій шрифт розміщується на 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.


2
у вас виникли проблеми, подібні до описаних тут - Access-Control-Allow-Originзаголовок отримує кешування та визнає недійсним CORS, коли подається наступний запит через інший субдомен?
OV

1
@ov У мене не виникає проблеми, оскільки я чітко встановлюю домени, які використовують ресурси. Я прочитав посилання, яке ви опублікували раніше. Я туманно запам'ятав деякі відповіді на інший потік, у яких сказано, що домени повинні бути явно вказані, тому <AllowedOrigin> * </AllowedOrigin> насправді не дозволено через деякі обмеження. Зараз я не можу знайти ці відповіді, це може бути повідомлення в блозі, яке я читала в інших місцях. Сподіваюся, що це допомагає.
VKen

3
Ви можете мати кілька елементів AllowedOrigin всередині одного елемента CORSRule, щоб ви могли об'єднати ці CORSRule в один елемент, оскільки інші елементи в них ідентичні.
Бен Халл

4
@dan, якщо відро S3 обслуговується CloudFront, схоже, що відповідь полягає в тому, щоб змінити запит шрифту за доменом, як це зафіксовано в цій офіційній відповіді Amazon: forums.aws.amazon.com/thread.jspa?threadID=114646
Джефф Етвуд

2
Це було надзвичайно засмучуючим питанням. Хороша новина полягає в тому, що тепер, здається, S3 робить все правильно, тому принаймні можна обслуговувати все, крім веб-шрифтів, через CloudFront та обслуговувати файли шрифтів безпосередньо з S3. На жаль, злом запитів не дуже практичний у нашому застосуванні без більш значного рефакторингу, оскільки всі активи подаються через конвеєр активів Rails, і немає зручного способу налаштувати URL-адреси активів під час запиту (вони генеруються під час розгортання коли активи попередньо складені). URL-адреса шрифту в css вже на S3.
Зак Ліптон

97

Після деяких налаштувань, здається, я змусив це працювати без злому рядка запиту. Більше інформації тут: http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/RequestAndResponseBehaviorS3Origin.html#RequestS3-cors

Я збираюся пройти всю свою установку, щоб було легко побачити, що я зробив, сподіваюся, це допомагає іншим.

Довідкова інформація: я використовую додаток Rails, у якого є gem_Anc_sync для розміщення активів на S3. Сюди входять шрифти.

У консолі S3 я натиснув своє відро, властивості та "редагувати конфігурацію корсів" тут: Кнопка конфігурації CORS

Всередині textarea у мене є щось на кшталт:

<?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 ) я створив дистрибутив, додав джерело, яке вказувало на моє відро S3 додавання походження

Потім додано поведінку для шляху за замовчуванням для вказівки на налаштування I на основі 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==

(Зверніть увагу, що вище було пропущено Cloudfront, оскільки ці файли кешуються протягом 180 секунд, але те саме працювало на зверненнях)

3) Натисніть на Cloudfront з іншим походженням (але таке, яке дозволено на 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, оскільки вони є лише ГОЛОВОЮ, я роблю це - я, щоб зробити його GET і прокрутити вгору.


Працювали тоді, коли всі інші цього не робили. Дякуємо, що знайшли час для публікації таких деталей!
iwasrobbed

Це працює!! FYI - У мене був величезний текст відповіді на http, коли випробовували це ... редагую відповідь, щоб використовувати це рішення для завитка ... stackoverflow.com/questions/10060098/…
Майкл Горхам

Класні спасибі хлопці - раді бачити, що це працює для інших.
Еймон Ган

Я не можу тобі сказати, наскільки ти нам допоміг! +1
нічого особливого - тут

1
+1 для додавання заголовка клієнта Originвід глядачів, щоб Cloudfront кешував об’єкт на основі цього заголовка (і пересилав заголовки CORS сервера назад користувачеві)
Sébastien Saunier

13

Мої шрифти подавались правильно до останнього поштовху до Heroku ... Я не знаю чому, але маска в CORS дозволеного походження перестала працювати. Я додав усі мої препро і домени до політики 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>

UPDATE: додати коментар http://localhost:PORTзанадто


1
Дякуємо, що поділилися цим рішенням. Це працювало для мене.
Райан Монтгомері

8

Ну, в документації зазначено, що ви можете дотримуватися конфігурацію як "субресурс cors у вашому відрі". Я вважав, що я створюю файл під назвою "cors" в корені мого відра з конфігурацією, але це не працює. Врешті-решт мені довелося увійти до області адміністрування Amazon S3 та додати конфігурацію в propertiesдіалоговому вікні мого відра.

S3 може використовувати кращу документацію ...


1
Так, але мені пощастило помітити деякі нові зміни інтерфейсу на панелі властивостей. Я редагував політику щодо ковшів, тому природно шукаю конфігурацію CORS на одній панелі.
VKen

працював на мене, я хотів встановити це у своїй програмі, хто знав, що це буде так просто
Richlewis

7

У налаштуваннях Amazon S3 CORS (відро S3 / дозволи / 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: https://stackoverflow.com/a/25305915/618464

Отже, використовуйте це :

<?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) і він буде працювати.


6

У моєму випадку я не визначив простір імен XML та версію в конфігурації CORS. Визначення тих, хто працював.

Змінено

<CORSConfiguration>

до

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

Працює і для мене. Мої шрифти розміщуються на самому відрі.
хамайлеон

Чому шаблон за замовчуванням не включає в себе це автоматично, мені не доводиться.
CoatedMoose

4

Є кращий і простіший спосіб!

Я особисто вважаю за краще використовувати мої піддомени 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/


Це зриває SSL, а точніше коштує багато грошей, щоб зробити з SSL, тому багато людей цього не роблять.
малетор

4

Ця конфігурація працювала для мене. Я можу перелічити об'єкти, отримати, оновити та видалити.

<?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>

вам потрібно змінити домен, як я тестував з localhost, просто подивіться на цю сторінку для CORS: docs.aws.amazon.com/AWSJavaScriptSDK/guide/…
Шахід

1
<ifModule mod_headers.c>

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

</ifModule>

Просте рішення


Дякую, що поділились! Дав мені ідею просто додати цей заголовок як "метадані" під час завантаження статичних активів у хмарний сховище. (Хоча так і буде працювати лише з 1 particular domainабо all domains)
Vinay Vissh

0

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

Я правильно налаштував CORS на S3. Завитка давала правильну відповідь із заголовком початку. Сафарі правильно вибирав шрифт. Тільки хром був не бажаючий прийняти CORS.

Не впевнений, що саме викликало поведінку. Повинно бути щось із "If-modified-since"


0

Це стосується не шрифтів, а зображень, це може бути кращим випадком, але як це сталося зі мною, це може статися з іншим. Я залишу це тут, сподіваючись, що це комусь допоможе:

Якщо у вас є сценарій "Я зробив усе, що вони сказали, але все ще не вийде", ймовірно, це проблема, пов’язана з кешем в 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>

-1

Так, звісно. Firefox підтримує CORS для шрифтів, як вимагає специфікація на веб-сторінці http://dev.w3.org/csswg/css3-fonts/#allowing-cross-origin-font-loading


Дякуємо за вашу швидку відповідь, Борис Збарський. Чи могли б ви показати деякі приклади конфігурацій для налаштувань S3 CORS?
VKen

Я ніколи не замислювався над налаштуванням S3 ... Що стосується того, що надсилати на рівні HTTP, якщо ви добре з ним просто надсилаючи "Access-Control-Allow-Origin: *" у відповіді HTTP для файлів шрифтів повинен працювати.
Борис Збарський

Дякую, я намагаюся дізнатися, як саме це зробити з конфігураціями S3 CORS.
VKen
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.