Amazon S3 CORS (Compartilhamento de resources entre origens) e carregamento de fonts entre domínios do Firefox

Houve um problema de longa data com o Firefox não carregando fonts de origem diferente da página atual. Geralmente, o problema surge quando as fonts são exibidas em CDNs.

Várias soluções foram levantadas em outras questões:

CSS @ font-face não funciona com o Firefox, mas funciona com o Chrome e o IE

Com a introdução do Amazon S3 CORS, existe uma solução usando o CORS para resolver o problema de carregamento de fonts no Firefox?

edit: Seria ótimo ver uma amostra da configuração do S3 CORS.

edit2: Eu encontrei uma solução de trabalho sem realmente entender o que ela fez. Se alguém puder fornecer explicações mais detalhadas sobre as configurações e a mágica de fundo que acontece na interpretação da configuração feita pela Amazon, ela será muito apreciada, assim como com nzifnab que ofereceu uma recompensa por ela.

    Atualização de 10 de setembro de 2014:

    Você não precisa mais fazer nenhum dos hacks de string de consulta abaixo, já que o Cloudfront suporta o CORS agora. Consulte http://aws.amazon.com/blogs/aws/enhanced-cloudfront-customization/ e esta resposta para mais informações: https://stackoverflow.com/a/25305915/308315


    OK, eu finalmente consegui as fonts trabalhando usando a configuração abaixo com um pequeno ajuste dos exemplos na documentação.

    Minhas fonts estão hospedadas no S3, mas lideradas pelo cloudfront.

    Não sei por que funciona, acho que é provável que o GET e Content-* sejam necessários.

    Se alguém proficiente com a configuração do Amazon S3 CORS puder lançar algumas luzes sobre isso, será muito apreciado.

     < ?xml version="1.0" encoding="UTF-8"?>   https://mydomain.com GET 3000 Content-* Host   https://*.mydomain.com GET 3000 Content-* Host   

    editar:

    Alguns desenvolvedores estão enfrentando problemas de armazenamento em cache do Cloudfront no header Access-Control-Allow-Origin . Esse problema foi abordado pela equipe da AWS no link ( https://forums.aws.amazon.com/thread.jspa?threadID=114646 ) abaixo, comentado por @ Jeff-Atwood.

    A partir do encadeamento vinculado, é aconselhável, como solução alternativa, usar uma Cadeia de Consulta para diferenciar entre chamadas de diferentes domínios. Vou reproduzir o exemplo abreviado aqui.

    Usando o curl para verificar os headers de resposta:

    Domínio A: a.domain.com

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

    Cabeçalhos de resposta do domínio 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 

    Domínio B: b.domain.com

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

    Cabeçalhos de resposta do domínio 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 

    Você notará que o Access-Control-Allow-Origin retornou valores diferentes, que passaram do cache do Cloudfront.

    Depois de alguns ajustes, parece que consegui que isso funcionasse sem o hack da string de consulta. Mais informações aqui: http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/RequestAndResponseBehaviorS3Origin.html#RequestS3-cors

    Eu vou passar por toda a minha configuração para que seja fácil ver o que eu fiz, espero que isso ajude os outros.

    Informações de Apoio: Estou usando um aplicativo Rails que possui a gem asset_sync para colocar resources no S3. Isso inclui fonts.

    Dentro do console do S3, cliquei no meu bucket, propriedades e ‘edit cors configuration’, aqui: Botão de configuração do CORS

    Dentro da textarea eu tenho algo como:

     < ?xml version="1.0" encoding="UTF-8"?>   https://*.example.com GET 3000 *   

    Em seguida, no painel Cloudfront ( https://console.aws.amazon.com/cloudfront/home ), criei uma distribuição, adicionei uma origem que apontava para meu bucket S3 adicionando uma origem

    Em seguida, adicionei um comportamento para um caminho padrão para apontar para a origem baseada em S3 que eu configurei. O que eu também fiz foi clicar nos headers da Whitelist e adicionar o Origin : adicionando cabeçalhos de comportamento e lista de permissões

    O que acontece agora é o seguinte, que acredito estar certo:

    1) Verifique se os headers S3 estão sendo configurados corretamente

     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) Verifique Cloudfront funciona com os headers

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

    (Observe que o acima foi uma falha de cloudfront porque esses arquivos são armazenados em cache por 180 segundos, mas o mesmo estava trabalhando em hits)

    3) Acerte a nuvem com uma origem diferente (mas que é permitida no CORS para o bucket do S3) – o Access-Control-Allow-Origin não é armazenado em cache! yay!

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

    Observe acima que o domínio foi alterado com sucesso sem um corte de string de consulta.

    Quando eu mudo o header Origin, parece haver sempre um X-Cache: Miss from cloudfront na primeira requisição e depois eu recebo o esperado X-Cache: Hit from cloudfront

    PS Vale a pena notar que ao fazer curl -I (capital I) NÃO mostrará os headers Access-Control-Allow-Origin como apenas um HEAD, eu faço -i para torná-lo um GET e rolar para cima.

    Minhas fonts foram servidas corretamente até o último push para Heroku … Eu não sei por que, mas o curinga no CORS permitiu origem parou de funcionar. Eu adicionei todos os meus domínios prepro e pro à política do CORS na configuração do bucket, e agora é assim:

       http://prepro.examle.com https://prepro.examle.com http://examle.com https://examle.com GET 3000 Authorization   

    UPDATE: adicione seu http://localhost:PORT também

    Bem, a documentação afirma que você pode colocar a configuração como “o subfonte de cors em seu balde”. Tomei isso para significar que eu criaria um arquivo chamado “cors” na raiz do meu bucket com a configuração, mas isso não funcionaria. No final, tive que fazer o login na área de administração do Amazon S3 e adicionar a configuração na checkbox de diálogo de properties do meu bucket.

    O S3 poderia usar alguma documentação melhor …

    No meu caso, não defini namespace e versão XML na configuração do CORS. Definindo aqueles trabalhados.

    Mudou

      

    para

     < ?xml version="1.0" encoding="UTF-8"?>  

    Existe uma maneira melhor e mais fácil!

    Eu pessoalmente prefiro usar meus subdomínios DNS para resolver esse problema. Se o meu CDN está por trás do cdn.myawesomeapp.com em vez de sdf73n7ssa.cloudfront.net, então os navegadores não vão surtar e bloqueá-los como problemas de segurança entre domínios.

    Para apontar seu subdomínio para seu domínio do AWS Cloudfront, acesse o painel de controle do AWS Cloudfront, selecione sua distribuição do Cloudfront e insira seu subdomínio do CDN no campo Nomes de domínio alternativos (CNAMEs). Algo como cdn.myawesomeapp.com vai fazer.

    Agora você pode acessar seu provedor de DNS (como o AWS Route 53) e criar um CNAME para cdn.myawesomeapp.com apontando para sdf73n7ssa.cloudfront.net.

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

    Essa configuração funcionou para mim. Eu posso listar object, recuperar, atualizar e excluir.

     < ?xml version="1.0" encoding="UTF-8"?>   http://localhost:3000 HEAD GET PUT POST DELETE * ETag x-amz-meta-custom-header   
      Header set Access-Control-Allow-Origin: http://domainurl.com  

    Solução Simples

    Na configuração do Amazon S3 CORS (S3 Bucket / Permissions / CORS), se você usar isto:

     < ?xml version="1.0" encoding="UTF-8"?>   * GET 3000 *  

    O CORS funciona bem para arquivos Javascript e CSS, mas não funciona para arquivos de fonts .

    Você precisa especificar o domínio para permitir que o CORS use o padrão expresso na resposta @VKen: https://stackoverflow.com/a/25305915/618464

    Então, use isto :

     < ?xml version="1.0" encoding="UTF-8"?>   * GET 3000 *   https://*.mydomain.com GET 3000 *   

    Lembre-se de replace “mydomain.com” pelo seu domínio.

    Depois disso, invalide o cache do CloudFront (CloudFront / Invalidations / Create Invalidation) e ele funcionará.

    Reiniciar meu aplicativo de boot de mola (servidor) resolveu o problema para mim.

    Eu tinha configurado o CORS corretamente no S3. A onda estava dando a resposta correta com o header de origem. O Safari estava buscando a fonte corretamente. Foi apenas o cromo que não estava disposto a aceitar o CORS.

    Não sei o que exatamente causou o comportamento. Deve ser algo a ver com If-modified-since

    Sim, claro. O Firefox suporta o CORS para fonts, assim como a especificação requer em http://dev.w3.org/csswg/css3-fonts/#allowing-cross-origin-font-loading

    Eu experimentei o mesmo problema. Eu não tive que adicionar um CNAME ao meu CDD para evitar problemas de domínio cruzado … Eu só tinha que fazer o seguinte:

    Vá para as propriedades do seu bucket -> Permissões -> Adicionar mais permissions -> Beneficiário: Todos e marque a opção ‘list’.

    Este é um exemplo gráfico. http://i.stack.imgur.com/KOEwy.png

    Espero que isso seja útil para alguém.