Как настроить "Access-Control-Allow-Origin" с рельсами, nginx и пассажиром?

Я не могу получить Access-Control-Allow-Origin для отображения в Chrome - моя конечная цель - настроить CORS для шрифтов с Rails, поэтому он работает в production с CloudFront. Пока что, я просто хочу заставить его работать в development. Я вижу заголовок через curl, но не Chrome.

Я использую Rails 4.0, и я пробовал все следующие...

Я настроил Gemfile и application.rb как пример стойки-корса для рельсов 4:

Gemfile

gem 'rack-cors', '~> 0.2.9', require: 'rack/cors'

конфигурации /application.rb

config.middleware.insert_before 'ActionDispatch::Static', 'Rack::Cors' do
    allow do
        origins '*'
        resource '*',
            :headers => :any,
            :methods => [:get, :options, :head]
    end
end

консоль рельсов

2.0.0-p481 :001 > Rails.env
 => "development"
2.0.0-p481 :002 > Hello::Application.config.serve_static_assets
 => true

bash

curl -i http://localhost:5000/assets/OpenSans-Regular-webfont.woff

Content-Type: application/font-woff
Content-Length: 22660
Connection: keep-alive
Status: 200 OK
Cache-Control: public, must-revalidate
Last-Modified: Wed, 30 Apr 2014 23:51:57 GMT
ETag: "467b34801137bd4031e139839ad86370"
X-Request-Id: c4b07b4d-1c43-44ea-9565-dfda66378f98
X-Runtime: 0.046007
X-Powered-By: Phusion Passenger 4.0.50
Date: Sat, 20 Sep 2014 04:39:38 UTC
Server: nginx/1.6.1 + Phusion Passenger 4.0.50

curl -i -H "Origin: http://localhost:5000" http://localhost:5000/assets/OpenSans-Regular-webfont.woff

Content-Type: application/font-woff
Content-Length: 22660
Connection: keep-alive
Status: 200 OK
Cache-Control: public, must-revalidate
Last-Modified: Wed, 30 Apr 2014 23:51:57 GMT
ETag: "467b34801137bd4031e139839ad86370"
Access-Control-Allow-Origin: http://localhost:5000   # adding
Access-Control-Allow-Methods: GET, OPTIONS, HEAD     # -H
Access-Control-Max-Age: 1728000                      # produced
Access-Control-Allow-Credentials: true               # these
Vary: Origin                                         # headers
X-Request-Id: b9666f30-416d-4b5b-946a-bdd432bc191c
X-Runtime: 0.050420
X-Powered-By: Phusion Passenger 4.0.50
Date: Sat, 20 Sep 2014 03:45:30 UTC
Server: nginx/1.6.1 + Phusion Passenger 4.0.50

Chrome (v37) Средства разработки > Сеть > OpenSans-Regular-webfont.woff > Заголовки > Заголовки ответов

HTTP/1.1 304 Not Modified
Connection: keep-alive
Status: 304 Not Modified
Cache-Control: no-cache
X-Request-Id: ac153b8c-e0cb-489d-94dd-90aacc10d715
X-Runtime: 0.116511
X-Powered-By: Phusion Passenger 4.0.50
Date: Sat, 20 Sep 2014 03:41:53 UTC
Server: nginx/1.6.1 + Phusion Passenger 4.0.50

Я также пробовал следующие альтернативы: различные источники:

config.middleware.insert_before 'ActionDispatch::Static', 'Rack::Cors' do
config.middleware.insert_after Rails::Rack::Logger, Rack::Cors do
config.middleware.insert_before Warden::Manager, Rack::Cors do
config.middleware.insert 0, Rack::Cors do
config.middleware.use Rack::Cors do

Я также попробовал следующее: applications.rb, как Как отобразить FontAwesome в Firefox с помощью Rails и CloudFront:

config.assets.header_rules = {
  :global => {'Cache-Control' => 'public, max-age=31536000'},
  :fonts  => {'Access-Control-Allow-Origin' => '*'}
}

Я также пробовал следующее в config.ru, согласно CloudFront CDN с Rails на Heroku

require 'rack/cors'
use Rack::Cors do
    allow do
        origins '*'
        resource '*', :headers => :any, :methods => :get 
    end 
end

связка промежуточного программного обеспечения exec

use Rack::Cors
use Rack::Sendfile
use ActionDispatch::Static
use Rack::Lock
use #<ActiveSupport::Cache::Strategy::LocalCache::Middleware:0x007f9ec21590b0>
use Rack::Runtime
use Rack::MethodOverride
use ActionDispatch::RequestId
use Rails::Rack::Logger
use ActionDispatch::ShowExceptions
use ActionDispatch::DebugExceptions
use ActionDispatch::RemoteIp
use ActionDispatch::Reloader
use ActionDispatch::Callbacks
use ActiveRecord::Migration::CheckPending
use ActiveRecord::ConnectionAdapters::ConnectionManagement
use ActiveRecord::QueryCache
use ActionDispatch::Cookies
use ActionDispatch::Session::CookieStore
use ActionDispatch::Flash
use ActionDispatch::ParamsParser
use Rack::Head
use Rack::ConditionalGet
use Rack::ETag
use Warden::Manager
use OmniAuth::Strategies::Facebook
run Hello::Application.routes

Я также пробовал font_assets безрезультатно.

Ответ 1

Линия Server заставила меня подумать, что, возможно, активы не обрабатываются Rails, а скорее nginx:

enter image description here

Это означает, что заголовки должны быть добавлены nginx, а не Rails, поэтому нам нужно настроить nginx. Оказывается, что возможность настройки nginx возможна с Passenger 4.0.39 - (вот соответствующий Git diff). Соответствующая документация доступна в Passenger Standalone в разделе Расширенная настройка.

Важное примечание в документации: исходный файл шаблона конфигурации может время от времени меняться, например. потому что новые функции внедряются в Phusion Passenger. Если ваш файл шаблона конфигурации не содержит требуемых изменений, эти новые функции могут работать некорректно. В худшем случае Standalone может даже работать неправильно. Поэтому каждый раз, когда вы обновляете Phusion Passenger, вы должны проверить, изменился ли исходный файл шаблона конфигурации, и смените любые изменения в свой собственный файл.

В отношении этой заметки в дополнение к настраиваемой копии файла конфигурации создайте "оригинальную" копию, которую вы можете diff всякий раз, когда вы обновляете Passenger.

bash

cp $(passenger-config about resourcesdir)/templates/standalone/config.erb config/nginx.conf.erb
cp config/nginx.conf.erb config/nginx.conf.erb.original

Затем добавьте --nginx-config-template config/nginx.conf.erb в строку web в Procfile.

PROCFILE

web: bundle exec passenger start -p $PORT --max-pool-size 3 --nginx-config-template config/nginx.conf.erb

конфигурации /nginx.conf.erb

Затем отредактируйте файл конфигурации config/nginx.conf.erb, найдя блок, который выглядит следующим образом:

    location @static_asset {
        gzip_static on;
        expires max;
        add_header Cache-Control public;
        add_header ETag "";
    }

... и добавьте две строки Access-Control:

    location @static_asset {
        gzip_static on;
        expires max;
        add_header Cache-Control public;
        add_header ETag "";
        add_header Access-Control-Allow-Origin *;
        add_header Access-Control-Request-Method *;
    }

Что это. Это будет работать в production, но не в development, из-за различий config.assets между ними.

config diff

diff не должен возвращать ничего сейчас, но если какие-либо будущие обновления для пассажира включают изменение этого файла, вы будете знать.

diff $(passenger-config about resourcesdir)/templates/standalone/config.erb config/nginx.conf.erb.original

Документация nginx

будущие улучшения

  • ограничить Allow-Origin
  • ограничить Request-Method
  • ограничивать оба заголовка только шрифтами

Ответ 2

ДА! Наконец-то.

user664833 ответить выше отлично, за исключением того, что я не могу найти файл конфигурации Passenger для редактирования.

Томас Най ответить здесь дает полный файл для создания в config/nginx.conf.erb:

    ##########################################################################
#  Passenger Standalone is built on the same technology that powers
#  Passenger for Nginx, so any configuration option supported by Passenger
#  for Nginx can be applied to Passenger Standalone as well. You can do
#  this by direct editing the Nginx configuration template that is used by
#  Passenger Standalone.
#
#  This file is the original template. DO NOT EDIT THIS FILE DIRECTLY.
#  Instead, make a copy of this file and pass the `--nginx-config-template`
#  parameter to Passenger Standalone.
#
#  Learn more about using the Nginx configuration template at:
#  https://www.phusionpassenger.com/library/config/standalone/intro.html#nginx-configuration-template
#
#  *** NOTE ***
#  If you customize the template file, make sure you keep an eye on the
#  original template file and merge any changes. New Phusion Passenger
#  features may require changes to the template file.
##############################################################

<%= include_passenger_internal_template('global.erb') %>

worker_processes 1;
events {
    worker_connections 4096;
}

http {
    <%= include_passenger_internal_template('http.erb', 4) %>

    ### 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

    ### END your own configuration options ###

    default_type application/octet-stream;
    types_hash_max_size 2048;
    server_names_hash_bucket_size 64;
    client_max_body_size 1024m;
    access_log off;
    keepalive_timeout 60;
    underscores_in_headers on;
    gzip on;
    gzip_comp_level 3;
    gzip_min_length 150;
    gzip_proxied any;
    gzip_types text/plain text/css text/json text/javascript
        application/javascript application/x-javascript application/json
        application/rss+xml application/vnd.ms-fontobject application/x-font-ttf
        application/xml font/opentype image/svg+xml text/xml;

    <% if @app_finder.multi_mode? %>
        # Default server entry for mass deployment mode.
        server {
            <%= include_passenger_internal_template('mass_deployment_default_server.erb', 12) %>
        }
    <% end %>

    <% for app in @apps %>
    server {
        <%= include_passenger_internal_template('server.erb', 8, true, binding) %>
        <%# <%= include_passenger_internal_template('rails_asset_pipeline.erb', 8, false) %1> %>

        ### 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
        # 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 "";
            if ($http_origin ~* ((https?:\/\/[^\/]*\.herokuapp\.com(:[0-9]+)?))) {
                add_header 'Access-Control-Allow-Origin' "$http_origin";
                add_header 'Access-Control-Allow-Credentials' 'true';
                add_header 'Access-Control-Allow-Methods' 'GET, HEAD';
                add_header 'Access-Control-Allow-Headers' 'Accept,Authorization,Cache-Control,Content-Type,DNT,If-Modified-Since,Keep-Alive,Origin,User-Agent,X-Mx-ReqToken,X-Requested-With';
            }
        }
        location @dynamic_request {
            passenger_enabled on;
        }

        ### END your own configuration options ###
    }
    passenger_pre_start <%= listen_url(app) %>;
    <% end %>

    <%= include_passenger_internal_template('footer.erb', 4) %>
}

Procfile должен включать строку:

web: bundle exec passenger start -p $PORT --max-pool-size 3 --nginx-config-template config/nginx.conf.erb

Вам также понадобится сконфигурировать ваш CDN Cloudfront, обслуживающий активы по ответу Guapolo

Настроить облачный центр CORS

В вашем дистрибутиве, который дает вам горя КОРС, перейдите на вкладку поведения и новое поведение, выбрав путь к активу, то есть /assets/icons.ttf и белый список "Происхождение" в соответствии с приведенным выше изображением.

Вам также может понадобиться в вашем дистрибутиве "аннулировать" старый кешированный ресурс на вкладке "Недействительные", т.е. ввести полное имя актива и кэша из вашего инспектора и аннулировать его. После того, как это обработано, разверните приложение с конфигурацией и перезапустите heroku. Вам нужно будет открыть страницу инспектора и "очистить кеш и перезагрузить".

Надеюсь, что это работает - это звучит как изменение конфигурации пассажира время от времени, поэтому мы можем найти этот перерыв, и ответ нужно будет обновить, чтобы отразить новую конфигурацию.

Ответ 3

Я не уверен, что это ответ, но похоже, что вы также можете попробовать самый простой способ с помощью after_filter с помощью:

headers['Access-Control-Allow-Origin'] = '*'
headers['Access-Control-Allow-Methods'] = 'POST, PUT, DELETE, GET, OPTIONS'
headers['Access-Control-Request-Method'] = '*'
headers['Access-Control-Allow-Headers'] = 'Origin, X-Requested-With, Content-Type, Accept, Authorization'
...