在 Ruby on Rails 中允许 CORS

Posted

技术标签:

【中文标题】在 Ruby on Rails 中允许 CORS【英文标题】:Allow CORS in Ruby on Rails 【发布时间】:2015-06-02 04:59:13 【问题描述】:

在我的config/application.rb 文件中,我有这段代码,

config.action_dispatch.default_headers = 
        'Access-Control-Allow-Origin' => '*',
        'Access-Control-Request-Method' => 'GET, PATCH, PUT, POST, OPTIONS, DELETE'
    

但这不允许我向我的服务器上的路由发送发布请求

Safari 出现此错误:

http://localhost:3000/studentsFailed to load resource: the server responded with a status of 404 (Not Found)
http://localhost:3000/studentsFailed to load resource: Origin http://localhost:4200 is not allowed by Access-Control-Allow-Origin.
localhost:1XMLHttpRequest cannot load http://localhost:3000/students. Origin http://localhost:4200 is not allowed by Access-Control-Allow-Origi

在我的 Rails 服务器控制台中:

Started OPTIONS "/students" for ::1 at 2015-03-28 21:00:45 -0500

ActionController::RoutingError (No route matches [OPTIONS] "/students"):

【问题讨论】:

【参考方案1】:

我花了一些时间来解决这个问题,我可以告诉你最可靠的解决方案是使用 rack-cors。见:https://github.com/cyu/rack-cors

首先添加gem:

gem 'rack-cors', '~> 0.3.1'

然后在application.rb添加

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

如果您的生产应用程序不提供静态资产(例如,如果您使用像 nginx 或 apache 这样的服务),请考虑将上述示例中的 ActionDispatch::Static 替换为 0。有关该参数的更多信息,请参阅https://github.com/cyu/rack-cors#common-gotchas。

【讨论】:

这应该可以。我使用ActionDispatch::Static 作为第一个参数而不是0 这对我来说非常有用。 @ReydiSutandang,你为什么建议ActionDispatch::Static 而不是0 现在我已经处理了一个新项目,我注意到这个解决方案对于更复杂的需求非常有意义。我已将其选为最佳答案 @ReydiSutandang 回到这个新项目并意识到ActionDispatch::Static 并不总是最好的答案。它通常比 0 好,但它不适用于许多环境(例如,如果您使用 NGINX 托管静态资产,在这种情况下,您的生产应用程序中不会有 ActionDispatch::Static)。如果您在生产中通过 Rails 提供静态资产(如果可以避免,这通常是一个坏主意),您应该使用 ActionDispatch::Static 而不是 0【参考方案2】:

在@Akiomi 的回答的帮助下,我能够解决这个问题:

在我的routes.rb 中,我在文件顶部添加了以下代码:

  match '(:anything)' => 'application#nothing', via: [:options]

接下来,在我的应用程序控制器中,我添加了:

def nothing
    render text: '', content_type: 'text/plain'
end

连同config/application.rb中的标题:

config.action_dispatch.default_headers = 
    'Access-Control-Allow-Origin' => '*',
    'Access-Control-Request-Method' => 'GET, PATCH, PUT, POST, OPTIONS, DELETE',
    'Access-Control-Allow-Headers:' => 'Origin, X-Requested-With, Content-Type, Accept'

是的,请注意我最初的问题中未包含的'Access-Control-Allow-Headers:' => 'Origin, X-Requested-With, Content-Type, Accept',这是大问题之一。

【讨论】:

【参考方案3】:

添加以下代码:

config/routes.rb:

match 'students' => 'students#option', via: [:options]

controllers/student_controller.rb:

def option
  render text: '', content_type: 'text/plain'
end

或者你可以使用rack-cors。

【讨论】:

【参考方案4】:

在某些情况下,浏览器会执行预检请求:它首先对同一 url 执行 OPTIONS 请求,而不是实际执行请求,以便它可以找出各种 CORS 标头的值是什么(更多关于预检here)。如果此请求成功并且标头具有正确的值,则它会执行实际请求。

您尚未为这些选项请求添加路由,因此它们将进入不包含 CORS 标头的 rails 404 页面。

OPTIONS 响应只需要设置与您在请求期间通常设置的相同的 CORS 标头。它不应该做任何其他事情。例如

match 'students' => 'students#cors_preflight', via: [:options]

def cors_preflight
  render nothing: true
end

请注意,您可能需要设置其他 CORS 标头,例如 Access-Control-Allow-CredentialsAccess-Control-Allow-Headers

当您完成这项工作后,您可能希望考虑稍微收紧一点 - 您可能会打开您的应用程序以进行跨站点脚本攻击。

【讨论】:

这是一个公共 api。我知道 404,但这不起作用,因为您还没有包含标题。下面我以一种有效的方式回答了我的问题。【参考方案5】:

轨道 5

config.middleware.insert_before 0, Rack::Cors do
  allow do
    origins '*'
    resource '*', headers: :any, methods: [:get, :post, :options]
  end
end

【讨论】:

以上是关于在 Ruby on Rails 中允许 CORS的主要内容,如果未能解决你的问题,请参考以下文章

思考Ruby On Rails的底层代码(Ruby on Rails 開發秘籍 | Ruby on Rails 快速入門)

ruby on rails如何安装

ruby 在Ruby on Rails中阻止别名

如何在 JavaScript 文件中允许空格?

在 symfony 访问控制中允许控制器操作

如何在 ruby​​ on rails 中访问 rails 助手和嵌入资产 javascript 文件中的 ruby​​?