Подтвердить что ты не робот

Rails отвечает с 404 по запросам опций предпросмотра CORS

Я создаю набор сервисов с использованием Rails 4, который я потребляю с помощью приложения браузера JavaScript. Cross-origin GETS работают нормально, но мои POST не справляются с опцией OPTIONS с ошибкой 404. По крайней мере, я думаю, что происходит. Вот ошибки, которые появляются в консоли. Это Chrome 31.0.1650.63 на Mac.

OPTIONS http://localhost:3000/confessor_requests 404 (Not Found) jquery-1.10.2.js:8706
OPTIONS http://localhost:3000/confessor_requests No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost' is therefore not allowed access. jquery-1.10.2.js:8706
XMLHttpRequest cannot load http://localhost:3000/confessor_requests. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost' is therefore not allowed access. main.html:1

Я искал высоко и низко для инструкций по включению CORS, и я в тупике. Обычная рекомендация, похоже, заключается в том, чтобы добавить что-то подобное в контроллер приложения, который я сделал.

before_filter :cors_preflight_check
after_filter :cors_set_access_control_headers

def cors_set_access_control_headers
  headers['Access-Control-Allow-Origin'] = '*'
  headers['Access-Control-Allow-Methods'] = 'POST, PUT, GET, OPTIONS'
  headers['Access-Control-Allow-Headers'] = '*'
  headers['Access-Control-Max-Age'] = "1728000"
end

def cors_preflight_check
  if request.method == :options
    headers['Access-Control-Allow-Origin'] = '*'
    headers['Access-Control-Allow-Methods'] = 'POST, PUT, GET, OPTIONS'
    headers['Access-Control-Allow-Headers'] = '*'
    headers['Access-Control-Max-Age'] = '1728000'
    render :text => '', :content_type => 'text/plain'
  end
end

Далее следует какой-то маршрут в route.rb, который будет перенаправляться на это действие, когда приходит запрос OPTIONS.

match "/*all" => "application#cors_preflight_check", :constraints => { :method => "OPTIONS" }

Директива 'match' больше не работает в Rails 4, поэтому я пошатнулся, пытаясь сделать ее прямо с помощью POSTS следующим образом:

post "/*all" => "application#cors_preflight_check", :constraints => { :method => :options }

Но это все еще не работает. Поскольку запросы GET работают, я предполагаю, что то, что мне не хватает, является правильным маршрутом для запроса OPTIONS. Тем не менее, я пробовал каждый маршрут, о котором я могу думать, и ничто не пропускает запрос.

Я также попытался установить cyu/rack-cors, и это дает тот же результат.

Кто-нибудь знает, что я делаю неправильно?

4b9b3361

Ответ 1

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

В моем случае драгоценный камень работал нормально, пока не использовал PUT (или PATCH или DELETE).

Если вы посмотрите в консоли разработчика браузера, посмотрите заголовки запроса, и у вас должна быть такая строка:

Access-Control-Request-Method: PUT

Важно отметить, что methods вы переходите к resource для Access-Control-Request-Method, а не к методу запроса, который должен пройти после предполетной проверки.

Обратите внимание, что у меня есть :methods => [:get, :post, :options, :delete, :put, :patch], который будет включать все методы, о которых я забочусь.

Таким образом, вся ваша конфигурация должна выглядеть примерно так: development.rb:

# This handles cross-origin resource sharing.
# See: https://github.com/cyu/rack-cors
config.middleware.insert_before 0, "Rack::Cors" do
  allow do
    # In development, we don't care about the origin.
    origins '*'
    # Reminder: On the following line, the 'methods' refer to the 'Access-
    # Control-Request-Method', not the normal Request Method.
    resource '*', :headers => :any, :methods => [:get, :post, :options, :delete, :put, :patch], credentials: true
  end
end

Ответ 2

Работа с Rails 3.2.11.

Я положил

match '*path', :controller => 'application', :action => 'handle_options_request', :constraints => {:method => 'OPTIONS'}

в файле routes.rb. Ключ должен был поставить его в качестве главного приоритета (поверх файла route.rb). Создал это действие, чтобы он был общедоступным:

  def handle_options_request
    head(:ok) if request.request_method == "OPTIONS"
  end

И фильтр в контроллере приложения:

 after_filter :set_access_control_headers

  def set_access_control_headers
    headers['Access-Control-Allow-Origin'] = '*'
    headers['Access-Control-Allow-Methods'] = 'GET, POST, PUT, DELETE'
  end

Ответ 3

Да, как указывали другие, есть GEM, чтобы сделать это лучше. Но так как мне очень понравился метод, указанный в исходном сообщении в блоге с кодом cors, я нашел решение Rails 4, если вы используете этот код.

В ваших route.rb:

match '*all' => 'my_method_name#cor', via: :options

В вашем контроллере my_method_name:

def cor
    # blank section for CORR
    render :text => ''
end

Пока у вас есть этот плюс ваш другой код:

before_filter :cors_preflight_check
after_filter :cors_set_access_control_headers
...

Затем вы должны быть настроены для Rails 4.

Ответ 4

Возможно, это поможет вам: API CORS в Rails 4

Он добавляет метод OPTIONS к определению маршрута и добавляет фильтр к базовому контроллеру API, который напрямую отвечает на запросы OPTIONS с правильным заголовком и также устанавливает правильные заголовки CORS для всех других действий.

Ответ 5

В этом случае возникли проблемы с Rails 4 и Devise. Я закончил использование Rack CORS middleware драгоценного камня от Calvin Yu. Отличный бесплатный блог статья.

Ответ 6

Я не уверен, какую фреймворк javascript вы используете (или если хотите), так как вы не уточнили, что вы делаете на стороне клиента, чтобы подключиться к вашему Rails 4 API, но я думал, что я добавьте мой ответ, если он поможет кому-нибудь.

Я столкнулся с одной и той же проблемой при подключении к Rails 4 API с самолетом Devise с фронтального интерфейса AngularJS (оба выполнялись на отдельных портах localhost). Я пытался войти в задний конец, используя запрос POST из формы AngularJS, но я продолжал получать ошибку 404 NOT FOUND, потому что я отправлял запрос OPTIONS с предполетным полем. Потребовалось более 2 дней, чтобы выяснить, как исправить эту проблему.

В основном вам необходимо настроить прокси-сервер для вашего интерфейса (Angular, Backbone, что угодно), чтобы подключиться к вашему API, чтобы ваш внешний интерфейс считал, что запрос использует тот же источник. Существуют некоторые простые решения для настройки Proxies с использованием GruntJS. Я использую Gulp для моего проекта с Gulp -Connect и proxy-middleware со следующей настройкой (на основе найденного решения здесь)

var gulp            = require('gulp'),
    connect         = require('gulp-connect');

gulp.task('devServer', function() {
      connect.server({
        root: './dist',
        fallback: './dist/index.html',
        port: 5000,
        livereload: true,
        middleware: function(connect, o) {
            return [ (function() {
                var url = require('url');
                var proxy = require('proxy-middleware');
                var options = url.parse('http://localhost:3000/');
                options.route = '/api';
                return proxy(options);
            })() ];
        }
      });
    });

Надеюсь, это поможет кому-то!

Ответ 7

Я столкнулся с той же проблемой и в настоящее время оцениваю следующие маршруты для любых возможных проблем безопасности/производительности. Они решают проблему, но...

match '/', via: [:options], 
 to:  lambda {|env| [200, {'Content-Type' => 'text/plain'}, ["OK\n"]]}
match '*unmatched', via: [:options],  
 to:  lambda {|env| [200, {'Content-Type' => 'text/plain'}, ["OK\n"]]}

Несмотря на то, что "матч", предположительно, не работает в Rails 4, очевидно, что он работает, если вы ограничиваете его определенным методом.