在 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-Credentials
、Access-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 中访问 rails 助手和嵌入资产 javascript 文件中的 ruby?