Rails 3,在Firefox生产环境中@font-face失败

23
我正在一个Rails 3应用中使用font-awesome,在开发模式下一切正常,但是当我将其推到Heroku后,Firefox无法渲染图标,取而代之的是这个:

enter image description here

  • Chrome在开发和生产环境中都可以正确渲染图标。
  • 这只影响Firefox(虽然我没有尝试IE)。
  • 应用程序位于here,我希望有人能确认这不仅仅发生在我的机器上(以帮助我排除本地主机缓存问题)。
  • 所有资产,包括字体和样式表,都托管在S3上,使用asset_sync gem。

我所做的:

将以下内容添加到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;
}

然后我将这个放在application.rb中:
# application.rb
config.assets.paths << Rails.root.join("app", "assets", "fonts")
config.assets.precompile += %w( .svg .eot .woff .ttf )

最终,我将所有4个字体文件放置在app/assets/fonts中。
我真的很想知道我在这里做错了什么。
7个回答

25

这是我在AWS管理控制台中为我的存储桶添加的配置,用于配置交叉访问:

登录AWS -> AWS管理控制台 -> S3 -> 找到您的存储桶 -> 点击属性按钮(纸张上的放大镜)-> 在右侧点击 PERMISSIONS -> “编辑 CORS 配置”

<CORSConfiguration>
    <CORSRule>
        <AllowedOrigin>*</AllowedOrigin>
        <AllowedMethod>GET</AllowedMethod>
        <MaxAgeSeconds>3000</MaxAgeSeconds>
        <AllowedHeader>Content-*</AllowedHeader>
        <AllowedHeader>Host</AllowedHeader>
    </CORSRule>
</CORSConfiguration>

经过两个小时的研究... :-(


2
如果这能让你感觉好一些,你刚刚帮我省下了两个小时。谢谢! - kateray
3
如果这能让你感觉更好,我浪费了三天在这上面。谢谢! - Hopstream
如何在Rails中实现此功能。 - Amit Suroliya
@AmitSuroliya:你是什么意思?这是Rails + AWS。问题出在AWS那边。 - ndemoreau
嘿...谢谢回复....我的意思是,我正在使用Rails 4,并且在生产Firefox中遇到了与font-awesome相关的问题。我将font-awesome文件作为部分scss使用,在Chrome、Safari等浏览器中完美运行。但是在Firefox中无法正常工作。我知道这是与CORS来源相关的问题,然后我尝试使用font_assets gem,但我的问题仍然存在。你能帮我吗?提前致谢.... - Amit Suroliya
只想补充一下如何使用它。登录AWS -> AWS管理控制台 -> S3 -> 找到您的Bucket -> 点击属性按钮(纸上放大镜)-> 在右侧点击“权限” -> “编辑CORS配置” -> 将此答案中的代码粘贴进去。一旦我弄清楚了该怎么做,它对我很有用,谢谢! - jerclarke

13

我的问题已经解决。

这篇文章中,我了解到:

除非设置了某些特定的头部信息,否则Firefox会拒绝所有跨站点字体请求:

[即Access-Control-Allow-Origin]

此外,从这篇文章中:

不幸的是,目前S3不允许您指定分配给对象的Access-Control-Allow-Origin头部信息。

所以你有几个选择:

  1. 从您应用程序的public文件夹中提供字体,而不是从S3中提供。
  2. 从Rackspace提供字体,在那里你可以设置头部信息。
  3. 将字体作为Base64字符串嵌入到您的样式表中。

由于这个网站不会有太多流量,我选择了第一种选项,但是在这里有一个很好的介绍,可以同时从Rackspace提供字体并从S3中提供所有其他资源服务字体


更新:

亚马逊昨天宣布他们现在支持跨域资源共享(CORS),因此上面发布的解决方案应该不再需要。请参阅他们的开发人员指南了解更多信息。


我遇到了同样的问题,只不过我的应用程序是托管在Heroku上。这些字体可以在Chrome、Chromium和Safari上加载,但无法在Firefox和IE8上加载。您能否指导我解决这个问题?我使用的是Rails 4,BS 3和Font Awesome。谢谢。 - Prasad Surase

6

1
谢谢,我昨天已经将该链接添加到被接受的答案中了,祝好。 - stephenmurdoch

5
您还可以使用一些Rack中间件直接提供带有所需访问控制标头的字体以供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

-----

这个解决方案使用规则来基于不同的规则为每个文件设置不同的头部信息。这些规则在这里描述:https://github.com/thomasklemm/butler#providing-rules-for-setting-http-headers。基本上,你可以使用正则表达式做任何事情,但是对于文件结尾、文件夹、Web字体和全局头部有快捷方式。


不错的提示,谢谢分享链接 - butler 看起来是一个非常有用的 gem。 - stephenmurdoch
1
最近,底层的Rack::File实现不允许设置自定义HTTP头。刚刚有一个提交被接受,引入了这个功能,但是还没有官方版本发布(将在1.4.2+中发布)。我期望Rails自己的ActionDispatch::Static将通过config.assets.http_header_rules = {}标志具有添加自定义头的功能。 - Thomas Klemm

1

1

0

这个主题有更新。似乎无法通过上传 cors.xml 文件到存储桶来设置 CORS。现在你需要手动点击它 ;)。这个主题在我寻找解决方案的时候节省了一些时间,但另一方面,我也花费了一些时间上传和更改 cors.xml 文件。

当前的解决方案是点击存储桶的属性 > 权限 > 然后点击添加 CORS 配置


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接