【问题标题】:Allow CORS in Ruby on Rails在 Ruby on Rails 中允许 CORS
【发布时间】: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"):

【问题讨论】:

    标签: ruby-on-rails ajax cors rails-api


    【解决方案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
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-12-15
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-12-05
          • 1970-01-01
          相关资源
          最近更新 更多