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
这是一个难以处理的问题,原因有二:
*
访问我们网站上*
资源的权限config/initializer/*.rb
文件来配置Rails,而不是编辑标准配置文件(如config.ru
或config/application.rb
),综上所述,以下是我的解决方案,我认为从2016年4月16日起,这是最好的:
gem "rack-cors"
机架cors gem在机架中间件中实现cors协议。
除了在批准的来源上设置Access Control Allow Origin和相关标题外,它还添加了一个Vary:Origin
响应标题,指示CloudFront分别缓存每个来源的响应(包括响应标题)。当我们的站点可以通过多个来源访问时(例如,通过http和https,以及通过“www.”和裸域访问),这一点至关重要## 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/ ]
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