Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/heroku/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby on rails Cloudfront CORS问题在Rails应用程序上提供字体_Ruby On Rails_Heroku_Fonts_Cors_Amazon Cloudfront - Fatal编程技术网

Ruby on rails Cloudfront CORS问题在Rails应用程序上提供字体

Ruby on rails Cloudfront CORS问题在Rails应用程序上提供字体,ruby-on-rails,heroku,fonts,cors,amazon-cloudfront,Ruby On Rails,Heroku,Fonts,Cors,Amazon Cloudfront,访问我的网站时,我一直从控制台收到此错误消息: font from origin 'https://xxx.cloudfront.net' has been blocked from loading by Cross-Origin Resource Sharing policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'https://www.example.com

访问我的网站时,我一直从控制台收到此错误消息:

font from origin 'https://xxx.cloudfront.net' has been blocked from loading by Cross-Origin Resource Sharing policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'https://www.example.com' is therefore not allowed access.
我什么都试过了:

  • 我已经安装了
  • 已配置application.rb文件

    config.font_assets.origin = 'http://example.com'
    
  • Cloudfront上的白名单标题,如至中所述

但是什么都没有,零,娜达


我正在Heroku上使用Rails 4.1。

我刚刚遇到了同样的问题,并设法解决了它

您已经正确地告诉Cloudfront允许使用这些标题,但是您没有将这些标题添加到Cloudfront获得字体的位置。是的,您的原始标题是允许的,但Heroku无论如何都不会用字体发送这些标题

要解决这个问题,您需要在Heroku上的字体中添加正确的CORS标题。幸运的是,这很容易

首先,将
rack/cors
gem添加到项目中

接下来,配置机架服务器,以便为其服务的任何资产加载和配置CORS。在应用程序预加载到
config.ru

require 'rack/cors'
use Rack::Cors do
  allow do
    origins '*'

    resource '/cors',
      :headers => :any,
      :methods => [:post],
      :credentials => true,
      :max_age => 0

    resource '*',
      :headers => :any,
      :methods => [:get, :post, :delete, :put, :patch, :options, :head],
      :max_age => 0
    end
  end
这将设置从Heroku返回的所有资源,以应用正确的CORS头。您可以根据文件和安全需要限制头的应用

一旦部署,进入Cloudfront并开始对之前给您CORS权限错误的任何内容进行无效化。现在,当Cloudfront从Heroku加载一个新副本时,它将具有正确的头,Cloudfront将按照先前配置的
Origin
权限将这些头传递给客户端

要确保从服务器提供正确的标头,可以使用以下curl命令验证标头:
curl-I-s-xget-H“来源:www.yoursite.com”http://www.yoursite.dev:5000/assets/fonts/myfont.svg

您应该看到返回的以下标题:

Access-Control-Allow-Origin: www.yoursite.com
Access-Control-Allow-Methods: GET, POST, DELETE, PUT, PATCH, OPTIONS, HEAD
Access-Control-Max-Age: 0
Access-Control-Allow-Credentials: true

这是一个难以处理的问题,原因有二:

  • CloudFront镜像了Rails应用程序的响应头,这一事实需要你改变主意。CORS协议很难理解,但现在你必须在两个层面上遵循它:在浏览器和CloudFront之间(当我们的Rails应用程序将其用作CDN时),以及在浏览器和Rails应用程序之间(当一些恶意网站想要滥用我们时)

    CORS实际上是关于浏览器和网页想要访问的第三方资源之间的对话。(在我们的用例中,这是CloudFront CDN,为我们的应用程序提供资产。)但由于CloudFront从我们的应用程序获取其访问控制响应头,我们的应用程序需要像CloudFront在说话一样提供这些头,同时,不授予会使其自身暴露于导致最初开发的同源策略/COR的滥用类型的权限。特别是,我们不应授予
    *
    访问我们网站上
    *
    资源的权限

  • 我在那里发现了太多过时的信息——没完没了的博客帖子和帖子。CloudFront已经显著改进了其CORS支持,尽管它仍然不完美。(COR真的应该是开箱即用的。)而宝石本身也在进化

  • 我的设置:运行在Heroku上的Rails 4.1.15,其资产由CloudFront提供。我的应用程序在“www.”和zone apex上响应http和https,而不进行任何重定向

    我简要地看了一下问题中提到的font_assets gem,但很快就放弃了它,转而选择了rack cors,这似乎更切题。我不想简单地打开所有来源和所有路径,因为这会破坏CORS点和同一来源策略的安全性,所以我需要能够指定允许的少数来源。最后,我个人倾向于通过单个
    config/initializer/*.rb
    文件来配置Rails,而不是编辑标准配置文件(如
    config.ru
    config/application.rb
    ),综上所述,以下是我的解决方案,我认为从2016年4月16日起,这是最好的:

  • Gemfile

    gem "rack-cors"
    
    机架cors gem在机架中间件中实现cors协议。 除了在批准的来源上设置Access Control Allow Origin和相关标题外,它还添加了一个
    Vary:Origin
    响应标题,指示CloudFront分别缓存每个来源的响应(包括响应标题)。当我们的站点可以通过多个来源访问时(例如,通过http和https,以及通过“www.”和裸域访问),这一点至关重要

  • config/initializers/rack cors.rb

    ## Configure Rack CORS Middleware, so that CloudFront can serve our assets.
    ## See https://github.com/cyu/rack-cors
    
    if defined? Rack::Cors
        Rails.configuration.middleware.insert_before 0, Rack::Cors do
            allow do
                origins %w[
                    https://example.com
                     http://example.com
                    https://www.example.com
                     http://www.example.com
                    https://example-staging.herokuapp.com
                     http://example-staging.herokuapp.com
                ]
                resource '/assets/*'
            end
        end
    end
    
    这告诉浏览器,它可能仅代表我们的Rails应用程序(而不是代表恶意的site.com)和
    /assets/
    URL(而不是控制器)访问Rails应用程序上的资源(并扩展到CloudFront,因为它正在镜像我们)。换句话说,允许CloudFront为资产提供服务,但不要超出我们的能力

    注:

    • 我试着在机架超时后插入它,而不是在中间件链的顶端。 它对dev有效,但对Heroku无效,尽管 具有相同的中间件(除Honeybadger之外)
    • 源代码列表也可以作为regexp完成。 注意在绳子的末端锚定图案

      origins [
          /\Ahttps?:\/\/(www\.)?example\.com\z/,
          /\Ahttps?:\/\/example-staging\.herokuapp\.com\z/
      ]
      
      但我认为只读取文本字符串更容易

  • 配置CloudFront,将浏览器的原始请求头传递到我们的Rails应用程序。

    奇怪的是,CloudFront似乎将Origin头从浏览器转发到我们的Rails应用程序,而不管我们是否将其添加到此处,但CloudFront仅在Origin明确添加到headers白名单(截至2016年4月)时才遵守我们应用程序的
    Vary:Origin
    缓存指令

    请求头w
    origins [
        /\Ahttps?:\/\/(www\.)?example\.com\z/,
        /\Ahttps?:\/\/example-staging\.herokuapp\.com\z/
    ]
    
    curl -H "Origin: https://tidyme-staging.com.au" -I http://tidyme-staging.com.au/assets/31907B_4_0-588bd4e720d4008295dcfb85ef36b233ee0817d7fe23c76a3a543ebba8e7c85a.ttf
    
    HTTP/1.1 200 OK
    Connection: keep-alive
    Server: nginx/1.10.0
    Date: Wed, 03 Aug 2016 00:29:37 GMT
    Content-Type: application/x-font-ttf
    Content-Length: 316664
    Last-Modified: Fri, 22 Jul 2016 03:31:57 GMT
    Expires: Thu, 31 Dec 2037 23:55:55 GMT
    Cache-Control: max-age=315360000
    Cache-Control: public
    Accept-Ranges: bytes
    Via: 1.1 vegur
    
    cp $(passenger-config about resourcesdir)/templates/standalone/config.erb config/passenger_config.erb
    
    <%# include_passenger_internal_template('rails_asset_pipeline.erb', 8, false) %>
    
    ### BEGIN your own configuration options ###
    # This is a good place to put your own config
    # options. Note that your options must not
    # conflict with the ones Passenger already sets.
    # Learn more at:
    # https://www.phusionpassenger.com/library/config/standalone/intro.html#nginx-configuration-template
    
    location ~ "^/assets/.+\.(woff|eot|svg|ttf|otf).*" {
        error_page 490 = @static_asset_fonts;
        error_page 491 = @dynamic_request;
        recursive_error_pages on;
    
        if (-f $request_filename) {
            return 490;
        }
        if (!-f $request_filename) {
            return 491;
        }
    }
    
    # Rails asset pipeline support.
    location ~ "^/assets/.+-([0-9a-f]{32}|[0-9a-f]{64})\..+" {
        error_page 490 = @static_asset;
        error_page 491 = @dynamic_request;
        recursive_error_pages on;
    
        if (-f $request_filename) {
            return 490;
        }
        if (!-f $request_filename) {
            return 491;
        }
    }
    
    location @static_asset {
        gzip_static on;
        expires max;
        add_header Cache-Control public;
        add_header ETag "";
    }
    
    location @static_asset_fonts {
        gzip_static on;
        expires max;
        add_header Cache-Control public;
        add_header ETag "";
        add_header 'Access-Control-Allow-Origin' '*';
        add_header 'Access-Control-Allow-Methods' 'GET, HEAD, OPTIONS';
        add_header 'Access-Control-Allow-Headers' '*';
        add_header 'Access-Control-Max-Age' 3628800;
    }
    
    location @dynamic_request {
        passenger_enabled on;
    }
    
    ### END your own configuration options ###
    
    web: bundle exec passenger start -p $PORT --max-pool-size 2 --nginx-config-template ./config/passenger_config.erb
    
    curl -H "Origin: https://tidyme-staging.com.au" -I http://tidyme-staging.com.au/assets/31907B_4_0-588bd4e720d4008295dcfb85ef36b233ee0817d7fe23c76a3a543ebba8e7c85a.ttf
    
    HTTP/1.1 200 OK
    Connection: keep-alive
    Server: nginx/1.10.0
    Date: Wed, 03 Aug 2016 01:43:48 GMT
    Content-Type: application/x-font-ttf
    Content-Length: 316664
    Last-Modified: Fri, 22 Jul 2016 03:31:57 GMT
    Expires: Thu, 31 Dec 2037 23:55:55 GMT
    Cache-Control: max-age=315360000
    Cache-Control: public
    Access-Control-Allow-Origin: *
    Access-Control-Allow-Methods: GET, HEAD, OPTIONS
    Access-Control-Allow-Headers: *
    Access-Control-Max-Age: 3628800
    Accept-Ranges: bytes
    Via: 1.1 vegur
    
    config.public_file_server.headers = {
      'Access-Control-Allow-Origin' => '*'
    }
    
    config.public_file_server.headers = {
      'Access-Control-Allow-Origin' => 'https://www.example.org'
    }
    
    @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;
    }
    
    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
    
    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
    
    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