在 Rails 的 Ruby 中允许 CORS
Allow CORS in Ruby on Rails
在我的 config/application.rb
文件中,我有这段代码,
config.action_dispatch.default_headers = {
'Access-Control-Allow-Origin' => '*',
'Access-Control-Request-Method' => 'GET, PATCH, PUT, POST, OPTIONS, DELETE'
}
但这不允许我向服务器上的路由发送 post 请求
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"):
添加以下代码:
在config/routes.rb
中:
match 'students' => 'students#option', via: [:options]
在controllers/student_controller.rb
中:
def option
render text: '', content_type: 'text/plain'
end
或者您可以使用 rack-cors.
在@Akiomi 的回答的帮助下,我能够解决这个问题:
在我的 routes.rb
中,我在文件顶部添加了以下代码:
match '(:anything)' => 'application#nothing', via: [:options]
接下来,在我的应用程序控制器中,我添加了:
def nothing
render text: '', content_type: 'text/plain'
end
与 config/application.rb
中的 headers 一起:
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'
未包含在我的原始问题中,这是大问题之一。
在某些情况下,浏览器会执行预检请求:它不是实际执行请求,而是首先对相同的 url 执行 OPTIONS 请求,以便它可以找出各种 CORS 的值headers 是(更多关于预检 here)。如果此请求成功并且 headers 具有正确的值,则它会执行实际请求。
您还没有为这些选项请求添加路由,因此它们将进入 rails 404 页面,该页面不包含 CORS headers。
OPTIONS 响应只需设置与您通常在请求期间设置的相同的 CORS headers。它不应该做任何其他事情。例如
match 'students' => 'students#cors_preflight', via: [:options]
def cors_preflight
render nothing: true
end
请注意,您可能需要设置其他 CORS headers,例如 Access-Control-Allow-Credentials
、Access-Control-Allow-Headers
当你完成这项工作后,你可能希望考虑稍微收紧它 - 你可能会打开你的应用程序以进行跨站点脚本攻击。
我花了一些时间研究这个,我可以告诉你最可靠的解决方案是使用 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。
Rails 5
config.middleware.insert_before 0, Rack::Cors do
allow do
origins '*'
resource '*', headers: :any, methods: [:get, :post, :options]
end
end
在我的 config/application.rb
文件中,我有这段代码,
config.action_dispatch.default_headers = {
'Access-Control-Allow-Origin' => '*',
'Access-Control-Request-Method' => 'GET, PATCH, PUT, POST, OPTIONS, DELETE'
}
但这不允许我向服务器上的路由发送 post 请求
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"):
添加以下代码:
在config/routes.rb
中:
match 'students' => 'students#option', via: [:options]
在controllers/student_controller.rb
中:
def option
render text: '', content_type: 'text/plain'
end
或者您可以使用 rack-cors.
在@Akiomi 的回答的帮助下,我能够解决这个问题:
在我的 routes.rb
中,我在文件顶部添加了以下代码:
match '(:anything)' => 'application#nothing', via: [:options]
接下来,在我的应用程序控制器中,我添加了:
def nothing
render text: '', content_type: 'text/plain'
end
与 config/application.rb
中的 headers 一起:
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'
未包含在我的原始问题中,这是大问题之一。
在某些情况下,浏览器会执行预检请求:它不是实际执行请求,而是首先对相同的 url 执行 OPTIONS 请求,以便它可以找出各种 CORS 的值headers 是(更多关于预检 here)。如果此请求成功并且 headers 具有正确的值,则它会执行实际请求。
您还没有为这些选项请求添加路由,因此它们将进入 rails 404 页面,该页面不包含 CORS headers。
OPTIONS 响应只需设置与您通常在请求期间设置的相同的 CORS headers。它不应该做任何其他事情。例如
match 'students' => 'students#cors_preflight', via: [:options]
def cors_preflight
render nothing: true
end
请注意,您可能需要设置其他 CORS headers,例如 Access-Control-Allow-Credentials
、Access-Control-Allow-Headers
当你完成这项工作后,你可能希望考虑稍微收紧它 - 你可能会打开你的应用程序以进行跨站点脚本攻击。
我花了一些时间研究这个,我可以告诉你最可靠的解决方案是使用 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。
Rails 5
config.middleware.insert_before 0, Rack::Cors do
allow do
origins '*'
resource '*', headers: :any, methods: [:get, :post, :options]
end
end