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


135

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

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

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

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

edit: Было бы здорово увидеть образец конфигурации 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>

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

Некоторые разработчики сталкиваются с проблемами, связанными с кешированием Access-Control-Allow-Originзаголовка Cloudfront . Эта проблема решена сотрудниками 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 01

3
У вас может быть несколько элементов AllowedOrigin внутри одного элемента CORSRule, поэтому вы можете объединить эти CORSRule в один элемент, поскольку остальные элементы в них идентичны.
— Бен Халл

4
@dan, если ведро S3 обслуживается CloudFront, похоже, что ответ заключается в изменении строки запроса шрифта по домену, как описано
— Джефф Этвуд

2
Это была чрезвычайно неприятная проблема. Хорошая новость заключается в том, что теперь S3, похоже, поступает правильно, поэтому, по крайней мере, можно обслуживать все, кроме веб-шрифтов, через CloudFront, а файлы шрифтов - непосредственно из S3. К сожалению, взлом строки запроса не очень практичен в нашем приложении без более значительного рефакторинга, поскольку все ресурсы обслуживаются через конвейер ресурсов Rails, и нет удобного способа настроить URL-адреса ресурсов во время запроса (все они генерируются во время развертывания когда активы предварительно скомпилированы). URL-адрес шрифта в css уже установлен на S3.
— Зак Липтон

97

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

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

Общая информация: я использую приложение 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 ) я создал дистрибутив, добавил источник, указывающий на мою корзину 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) Нажмите 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, поскольку это только HEAD, я делаю -i, чтобы сделать его GET и прокручивать вверх.


Работало, когда все остальные - нет. Спасибо, что нашли время опубликовать такую ​​подробную информацию!
— iwasrobted

Оно работает!! К вашему сведению - при тестировании у меня был огромный текст ответа http ... собираюсь отредактировать ответ, чтобы использовать это решение curl ... stackoverflow.com/questions/10060098/…
— Майкл Горхэм

Круто спасибо, ребята - рад видеть, что это работает для других.
— Eamonn Gahan

Не могу передать, насколько вы нам помогли! +1
— ничего особенного

1
+1 за добавление заголовка клиента Originиз средств просмотра, чтобы Cloudfront кэшировал объект на основе этого заголовка (и пересылал серверные заголовки CORS обратно пользователю)
— Себастьен Сонье

13

Мои шрифты обслуживались правильно до последнего нажатия на 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тоже


1
Спасибо, что поделились этим решением. Это сработало для меня.
— Райан Монтгомери

8

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

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


1
Да, но мне посчастливилось заметить некоторые новые изменения интерфейса на панели свойств. Я редактировал политики корзины, поэтому, естественно, я ищу конфигурацию CORS на той же панели.
— VKen 01

сработало для меня, я хотел установить это в своем приложении, кто знал, что это будет так просто
— Richlewis

7

В конфигурации 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: 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/">

У меня тоже работает. Мои шрифты размещены в самом ведре.
— khamaileon

Я не понимаю, почему шаблон по умолчанию не включает это автоматически.
— CoatedMoose

4

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

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

Чтобы указать свой субдомен на домен AWS Cloudfront, перейдите в панель управления AWS Cloudfront, выберите дистрибутив Cloudfront и введите свой субдомен CDN в поле Альтернативные доменные имена (CNAME). Что-то вроде 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 стоит больших денег, поэтому многие люди этого не делают.
— maletor

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>

вам нужно сменить домен, так как я тестировал с локального хоста, просто посмотрите на эту страницу для 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. Curl давал правильный ответ с заголовком origin. Safari правильно загружал шрифт. Только хром не захотел принять 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 03

Я никогда не рассматривал настройку S3 ... Что касается того, что отправлять на уровне HTTP, если вы в порядке, просто отправьте «Access-Control-Allow-Origin: *» в HTTP-ответе для файлов шрифтов должно сработать.
— Борис Збарский

Спасибо, я пытаюсь выяснить, как именно сделать эту настройку с конфигурациями S3 CORS.
— VKen 06
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.