Rails Responds with 404 on CORS Preflight Options Request

大兔子大兔子 提交于 2019-11-28 09:35:18

Here's a solution with the rack-cors gem, which you said you tried. As others have mentioned, you didn't give much detail in regards to which front-end framework you're using and what the actual request looks like. So the following may not apply to you, but I hope it helps someone.

In my case, the gem worked fine until I used PUT (or PATCH or DELETE).

If you look in your browser developer console, look at the request headers, and you should have a line like this:

Access-Control-Request-Method: PUT

The important thing to note is that the methods you pass to resource are for the Access-Control-Request-Method, not the Request Method that is to come after the pre-flight check.

Note how I have :methods => [:get, :post, :options, :delete, :put, :patch] that will include all the methods I care about.

Thus your entire config section should look something like this, for 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

Working on Rails 3.2.11.

I put

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

in my routes.rb file. The key was to put it as top priority (on top of the routes.rb file). Created that action so that it is publicly available:

  def handle_options_request
    head(:ok) if request.request_method == "OPTIONS"
  end

And a filter in application controller:

 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

Yes, as others have pointed out there is a GEM to maybe do this better. But since I very much liked the method pointed out in the original blog post with the cors code, I've found the Rails 4 solution if you're using that code.

In your routes.rb:

match '*all' => 'my_method_name#cor', via: :options

In your my_method_name controller:

def cor
    # blank section for CORR
    render :text => ''
end

As long as you have that plus your other code:

before_filter :cors_preflight_check
after_filter :cors_set_access_control_headers
...

Then you should be set for Rails 4.

Perhaps this gist can help you: CORS in Rails 4 APIs

It adds the OPTIONS method to the route definition, and adds a filter to the API base controller which directly responds to OPTIONS requests with the correct header, and sets the correct CORS headers for all other actions, too.

Ran into this issue with Rails 4 and Devise. I ended up using Rack CORS middleware gem by Calvin Yu. A great complimentary blog article.

I'm not sure what javascript front end framework you are using (or if you are) since you didn't elaborate on what you are doing on the client-side to connect to your Rails 4 API, but I thought I'd add my answer in case it helps anybody.

I ran into the exact same problem while connecting to a Rails 4 API with the Devise gem from an AngularJS front end (both were running on separate localhost ports). I was trying to log in to the back end using a POST request from an AngularJS form but I kept getting a 404 NOT FOUND error because I was sending an OPTIONS request with preflight. It took more than 2 days to figure out how to fix the problem.

Basically you need to set up a proxy server for your front end (Angular, Backbone, whatever) in order to connect to your API so that your front end thinks that the request is using the same origin. There are some straightforward solutions out there for setting up Proxies using GruntJS. I am using Gulp for my project with Gulp-Connect and proxy-middleware with the following setup (based on the solution found here):

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

I hope this helps someone!

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.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!