46

我正在使用 Rails 4 创建一组服务,我正在使用 JavaScript 浏览器应用程序。跨域 GETS 工作正常,但我的 POST 未通过预检 OPTIONS 检查并出现 404 错误。至少,我认为这就是正在发生的事情。以下是控制台中出现的错误。这是 Mac 上的 Chrome 31.0.1650.63。

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

接下来是 routes.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,这给出了相同的结果。

有人知道我在做什么错吗?

4

8 回答 8

27

这是您说您尝试过的rack-cors gem的解决方案。正如其他人所提到的,您没有详细说明您正在使用哪个前端框架以及实际请求的外观。因此,以下内容可能不适用于您,但希望对某人有所帮助。

就我而言,在我使用 PUT(或 PATCH 或 DELETE)之前,gem 运行良好。

如果您查看浏览器开发人员控制台,请查看请求标头,您应该有如下一行:

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
于 2015-05-19T09:03:27.913 回答
11

在 Rails 3.2.11 上工作。

我放

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

在我的 routes.rb 文件中。关键是将其作为最高优先级(在 routes.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
于 2014-03-16T20:47:55.920 回答
7

是的,正如其他人指出的那样,有一个 GEM 可能会做得更好。但是由于我非常喜欢原始博客文章中使用 cors 代码指出的方法,因此如果您使用该代码,我已经找到了Rails 4解决方案。

在您的 routes.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 设置。

于 2015-05-06T04:28:38.120 回答
4

也许这个要点可以帮助你:Rails 4 APIs 中的 CORS

它将OPTIONS方法添加到路由定义中,并将过滤器添加到 API 基本控制器,该控制器OPTIONS使用正确的标头直接响应请求,并为所有其他操作设置正确的 CORS 标头。

于 2014-07-10T09:21:27.787 回答
2

I ran into the same issue, and am currently evaluating the following routes for any possible security / performance issues. They solve the issue, but...

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"]]}

Despite 'match' supposedly not working in Rails 4, apparently it does work if you restrict it to a specific method.

于 2014-11-27T04:00:46.310 回答
2

Rails 4 和 Devise 遇到了这个问题。我最终使用了 Calvin Yu 的Rack CORS middleware gem。一篇很棒的免​​费博客文章

于 2015-03-23T00:35:27.650 回答
1

我不确定您正在使用什么 javascript 前端框架(或者如果您正在使用),因为您没有详细说明您在客户端正在做什么以连接到 Rails 4 API,但我想我会添加我的回答,以防它帮助任何人。

我在使用 AngularJS 前端的 Devise gem 连接到 Rails 4 API 时遇到了完全相同的问题(两者都在不同的本地主机端口上运行)。我试图使用来自 AngularJS 表单的 POST 请求登录到后端,但我一直收到 404 NOT FOUND 错误,因为我正在发送带有预检的 OPTIONS 请求。花了超过 2 天的时间才弄清楚如何解决这个问题。

基本上,您需要为您的前端(Angular、Backbone 等)设置一个代理服务器,以便连接到您的 API,以便您的前端认为请求使用的是同一来源。有一些直接的解决方案可以使用 GruntJS 设置代理。我正在为我的项目使用 Gulp,其中包含 Gulp-Connect 和代理中间件,设置如下(基于此处找到的解决方案):

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);
            })() ];
        }
      });
    });

我希望这可以帮助别人!

于 2014-08-01T23:24:06.230 回答
0

这是带有 gem rack-cors的 Rails 5 解决方案。

0) 我们想要做什么?

这是一篇关于CORS(Cross-Origin Resource Sharing)的超级清晰的文章。

您的应用需要接受预检请求,这些OPTIONS请求是使用如下特殊标头发出的请求。在这种情况下,浏览器正在检查来自 的 POST 请求的授权,https://some-site.com给定Request-Headers的可以是任何东西。

Origin: https://some-site.com 
Access-Control-Request-Method: POST 
Access-Control-Request-Headers: x-csrf-ump-token

并使用适当的标题响应简单的文本内容(没关系),如下所示:

Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, PUT, PATCH, DELETE, OPTIONS, HEAD
Access-Control-Allow-Headers: x-csrf-ump-token
Access-Control-Max-Age: 1728000

注意:Access-Control-Allow-Headers是可选的。我们将它设置在any下面。

1) 处理 OPTIONS 请求

# config/routes.rb
match '*all', to: 'cors#preflight_check', via: [:options]

# app/controllers/cors_controller.rb
class CorsController < ApplicationController
  def preflight_check
    render plain: 'OK!'
  end
end

2)现在添加带有机架的正确标题

# config/initializers/cors.rb

# Handle Cross-Origin Resource Sharing (CORS) in order to accept cross-origin AJAX requests.
# Read more: https://github.com/cyu/rack-cors

Rails.application.config.middleware.insert_before 0, Rack::Cors do
  allow do
    origins '*'

    resource '*',
      headers: :any,
      methods: [:get, :post, :put, :patch, :delete, :options, :head],
      max_age: 1728000
  end
end

查看这篇文章以进一步自定义此配置,用于各种来源。

于 2021-03-08T17:11:16.227 回答