Cloudfront CORS issue serving fonts on Rails application

后端 未结 5 2037
栀梦
栀梦 2021-01-31 10:07

I keep receiving this error message from the console when visiting my website:

font from origin \'https://xxx.cloudfront.net\' has been blocked from loading by C         


        
5条回答
  •  小蘑菇
    小蘑菇 (楼主)
    2021-01-31 10:26

    Here is a repo the demonstrates serving a custom font with Rails 5.2 that works on Heroku. It goes further and optimizes serving the fonts to be as fast as possible according to https://www.webpagetest.org/

    https://github.com/nzoschke/edgecors

    Asset Pipeline and SCSS

    • Place fonts in app/assets/fonts
    • Place the @font-face declaration in an scss file and use the font-url helper

    From app/assets/stylesheets/welcome.scss:

    @font-face {
      font-family: 'Inconsolata';
      src: font-url('Inconsolata-Regular.ttf') format('truetype');
      font-weight: normal;
      font-style: normal;
    }
    
    body {
      font-family: "Inconsolata";
      font-weight: bold;
    }
    

    Serve from CDN with CORS

    I'm using CloudFront, added with the Heroku Edge addon.

    If you're using your own CloudFront, make sure to configure it to forward the browser Origin header to your backend origin.

    First configure a CDN prefix and default Cache-Control headers in production.rb:

    Rails.application.configure do
      # e.g. https://d1unsc88mkka3m.cloudfront.net
      config.action_controller.asset_host = ENV["EDGE_URL"]
    
      config.public_file_server.headers = {
        'Cache-Control' => 'public, max-age=31536000'
      }
    end
    

    If you try to access the font from the herokuapp.com URL to the CDN URL, you will get a CORS error in your browser:

    Access to font at 'https://d1unsc88mkka3m.cloudfront.net/assets/Inconsolata-Regular.ttf' from origin 'https://edgecors.herokuapp.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. edgecors.herokuapp.com/ GET https://d1unsc88mkka3m.cloudfront.net/assets/Inconsolata-Regular.ttf net::ERR_FAILED

    So configure CORS to allow access to the font from Heroku to the CDN URL:

    module EdgeCors
      class Application < Rails::Application
        # Initialize configuration defaults for originally generated Rails version.
        config.load_defaults 5.2
    
        config.middleware.insert_after ActionDispatch::Static, Rack::Deflater
    
        config.middleware.insert_before 0, Rack::Cors do
          allow do
            origins %w[
              http://edgecors.herokuapp.com
              https://edgecors.herokuapp.com
            ]
            resource "*", headers: :any, methods: [:get, :post, :options]
          end
        end
      end
    end
    

    Serve gzip Font Asset

    The asset pipeline builds a .ttf.gz file but doesn't serve it. This monkey patch changes the asset pipeline gzip whitelist to a blacklist:

    require 'action_dispatch/middleware/static'
    
    ActionDispatch::FileHandler.class_eval do
      private
    
        def gzip_file_path(path)
          return false if ['image/png', 'image/jpeg', 'image/gif'].include? content_type(path)
          gzip_path = "#{path}.gz"
          if File.exist?(File.join(@root, ::Rack::Utils.unescape_path(gzip_path)))
            gzip_path
          else
            false
          end
        end
    end
    

    The ultimate result is a custom font file in app/assets/fonts served from a long-lived CloudFront cache.

提交回复
热议问题