可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I'm using font-awesome in a rails 3 app, and everything is ok in development mode, but when I push to Heroku, Firefox fails to render the icons, and instead, I see this:
- Chrome renders the icons fine in development and production
- This just affects FireFox (although I've not tried IE)
- The app is here, I'd appreciate if someone could confirm that this is not just happening on my machine (to help me rule out a localhost caching issue).
- All assets, including fonts and stylesheets, are hosted on S3, using the asset_sync gem.
Here's what I've done:
Added the following to the top of font-awesome.css.scss:**
// font-awesome.css.scss
@font-face {
font-family: 'FontAwesome';
src: font-url("fontawesome-webfont.eot");
src: font-url("fontawesome-webfont.eot?#iefix") format("eot"),
font-url("fontawesome-webfont.woff") format("woff"),
font-url("fontawesome-webfont.ttf") format("truetype"),
font-url("fontawesome-webfont.svg#FontAwesome") format("svg");
font-weight: normal;
font-style: normal;
}
Then I put this in application.rb:
# application.rb
config.assets.paths << Rails.root.join("app", "assets", "fonts")
config.assets.precompile += %w( .svg .eot .woff .ttf )
Finaly I placed all 4 font files in app/assets/fonts
.
I would really like to know what I'm doing wrong here.
回答1:
This is the configuration I added to my bucket in AWS management console to configure this cross thing:
Log in to AWS -> AWS Management Console -> S3 -> Find your Bucket -> Push properties button (magnifying glass on paper for some reason) -> Clic PERMISSIONS on the right -> "Edit CORS configuration"
<CORSConfiguration>
<CORSRule>
<AllowedOrigin>*</AllowedOrigin>
<AllowedMethod>GET</AllowedMethod>
<MaxAgeSeconds>3000</MaxAgeSeconds>
<AllowedHeader>Content-*</AllowedHeader>
<AllowedHeader>Host</AllowedHeader>
</CORSRule>
</CORSConfiguration>
After two hours of researches... :-(
回答2:
I fixed my problem.
From this article, I learned that:
Firefox rejects all cross-site font requests unless some specific headers are set:
[i.e. Access-Control-Allow-Origin]
And, from this article:
Sadly, right now S3 doesn’t allow you to specify the Access-Control-Allow-Origin header that your objects get served with
So you have a few options:
- Serve the fonts from your app's public folder, not from S3
- Serve the fonts from Rackspace, where you can set the headers
- Embed the font in your as a Base64 string
I've gone with the first option since this is gonna be a low traffic site, but here's a nice write-up on how to serve fonts from Rackspace whilst simultaneously serving all other assets from S3.
UPDATE:
Amazon announced yesterday that they now support Cross Origin Resource Sharing (CORS), so the solution posted above should no longer be necessary. Their developer guide explains more.
回答3:
Amazon S3 now support CORS, you're no longer forced to embed BASE64 fonts in your css (it will save you some bandwidth :)
http://aws.amazon.com/about-aws/whats-new/2012/08/31/amazon-s3-announces-cross-origin-resource-sharing-CORS-support/
回答4:
You can also use some rack middleware to serve the fonts directly with the required access-control headers to cloudfront.
# config/environment/production.rb
# Rack Headers
# Set HTTP Headers on static assets
config.assets.header_rules = {
:global => {'Cache-Control' => 'public, max-age=31536000'},
:fonts => {'Access-Control-Allow-Origin' => '*'}
}
require 'rack_headers'
config.middleware.insert_before '::ActionDispatch::Static', '::Rack::Headers'
-----
# lib/rack_headers.rb
require 'rack/utils'
module Rack
class Headers
def initialize(app, options={})
@app = app
default_path = Rails.application.config.assets.prefix || '/assets'
@asset_path = options.fetch(:path, default_path)
default_rules = Rails.application.config.assets.header_rules || {}
@rules = options.fetch(:header_rules, default_rules)
end
def call(env)
dup._call(env)
end
def _call(env)
status, @headers, response = @app.call(env)
@path = ::Rack::Utils.unescape(env['PATH_INFO'])
if @path.start_with?(@asset_path)
set_headers
end
[status, @headers, response]
end
def set_headers
@rules.each do |rule, headers|
case rule
when :global # Global
set_header(headers)
when :fonts # Fonts Shortcut
set_header(headers) if @path.match %r{\.(?:ttf|otf|eot|woff|svg)\z}
when Array # Extension/Extensions
extensions = rule.join('|')
set_header(result) if @path.match %r{\.(#{extensions})\z}
when String # Folder
set_header(result) if
(@path.start_with? rule || @path.start_with?('/' + rule))
when Regexp # Flexible Regexp
set_header(result) if @path.match rule
else
end
end
end
def set_header(headers)
headers.each { |field, content| @headers[field] = content }
end
end
end
-----
This solution uses rules for setting different headers on every file based on rules. The rules are described here: https://github.com/thomasklemm/butler#providing-rules-for-setting-http-headers. Basically you can do anything with Regexps, but there are shortcuts for file endings, folders, web fonts and global headers.
回答5:
You can use the following site to Base64 Encode a font. Tried using FontSquirel but it does not let you encrypt copyright / bought fonts.
http://base64fonts.com/convert.php
回答6:
Simply add the header for your whole bucket in s3.
http://aws.typepad.com/aws/2012/08/amazon-s3-cross-origin-resource-sharing.html
回答7:
There's an update to this thread. It seems that it's not possible to set CORS by uploading cors.xml file to a bucket. Now you have to CLICK it ;). This thread saved me some time while looking for a solution, but on the other hand I lost some time uploading and changing cors.xml file.
The current solution is to click on a bucket's properties > Permissons > and then click Add CORS Configuration