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, и это дает тот же результат.
Кто-нибудь знает, что я делаю неправильно?
Ответы
Ответ 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, очевидно, что он работает, если вы ограничиваете его определенным методом.