Rails répond avec 404 sur la demande d’options de contrôle en amont CORS

Je crée un ensemble de services à l’aide de Rails 4, que je consum avec une application de navigateur JavaScript. Le GETS d’origine croisée fonctionne correctement, mais mes tests POST échouent à la vérification OPTIONS en amont avec une erreur 404. Au moins, je pense que c’est ce qui se passe. Voici les erreurs telles qu’elles apparaissent dans la console. Ceci est Chrome 31.0.1650.63 sur un Mac.

OPTIONS http://localhost:3000/confessor_requests 404 (Not Found) jquery-1.10.2.js:8706 OPTIONS http://localhost:3000/confessor_requests No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost' is therefore not allowed access. jquery-1.10.2.js:8706 XMLHttpRequest cannot load http://localhost:3000/confessor_requests. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost' is therefore not allowed access. main.html:1 

J’ai cherché haut et bas pour obtenir des instructions sur l’activation de CORS, et je suis déconcerté. La recommandation habituelle semble être de mettre quelque chose comme ceci dans le contrôleur d’application, ce que j’ai fait.

 before_filter :cors_preflight_check after_filter :cors_set_access_control_headers def cors_set_access_control_headers headers['Access-Control-Allow-Origin'] = '*' headers['Access-Control-Allow-Methods'] = 'POST, PUT, GET, OPTIONS' headers['Access-Control-Allow-Headers'] = '*' headers['Access-Control-Max-Age'] = "1728000" end def cors_preflight_check if request.method == :options headers['Access-Control-Allow-Origin'] = '*' headers['Access-Control-Allow-Methods'] = 'POST, PUT, GET, OPTIONS' headers['Access-Control-Allow-Headers'] = '*' headers['Access-Control-Max-Age'] = '1728000' render :text => '', :content_type => 'text/plain' end end 

Suivi par une sorte de route dans routes.rb qui redirecta vers cette action lorsqu’une requête OPTIONS apparaît.

 match "/*all" => "application#cors_preflight_check", :constraints => { :method => "OPTIONS" } 

La directive ‘match’ ne fonctionne plus dans Rails 4, alors je l’ai sortingpatouillé, essayant de faire correspondre directement POSTS, comme ceci:

 post "/*all" => "application#cors_preflight_check", :constraints => { :method => :options } 

Mais ça ne marche toujours pas. Étant donné que les requêtes GET fonctionnent, je suppose que ce qui me manque est la route correcte pour la requête OPTIONS. Cependant, j’ai essayé tous les chemins possibles, et rien ne semble laisser passer la demande.

J’ai également essayé d’installer cyu / rack-cors , ce qui donne le même résultat.

Quelqu’un sait ce que je fais mal?

Voici une solution avec la gemme rack-cors , que vous avez dit avoir essayée. Comme d’autres l’ont mentionné, vous n’avez pas donné beaucoup de détails sur le framework que vous utilisez et à quoi ressemble la requête. Donc, ce qui suit peut ne pas s’appliquer à vous, mais j’espère que cela aidera quelqu’un.

Dans mon cas, la gemme a bien fonctionné jusqu’à ce que j’utilise PUT (ou PATCH ou DELETE).

Si vous regardez dans la console de développement de votre navigateur, regardez les en-têtes de la requête et vous devriez avoir une ligne comme celle-ci:

 Access-Control-Request-Method: PUT 

La chose importante à noter est que les methods vous transmettez aux resource concernent la Access-Control-Request-Method , et non la méthode de requête qui doit être effectuée après le contrôle avant vol.

Notez comment j’ai :methods => [:get, :post, :options, :delete, :put, :patch] qui inclura toutes les méthodes qui me tiennent à cœur.

Ainsi, toute votre section de configuration devrait ressembler à ceci, pour 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 

Travailler sur les rails 3.2.11.

je mets

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

dans mon fichier routes.rb. La clé était de le mettre en priorité (en haut du fichier routes.rb). A créé cette action pour la rendre accessible au public :

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

Et un filtre dans le contrôleur d’application:

  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 

Oui, comme d’autres l’ont fait remarquer, il y a peut-être un GEM pour faire mieux. Mais comme j’ai beaucoup aimé la méthode indiquée dans le billet de blog d’origine avec le code cors, j’ai trouvé la solution Rails 4 si vous utilisez ce code.

Dans vos routes.rb:

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

Dans votre contrôleur my_method_name:

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

Tant que vous avez cela plus votre autre code:

 before_filter :cors_preflight_check after_filter :cors_set_access_control_headers ... 

Ensuite, vous devriez être réglé pour Rails 4.

Peut-être que cet élément peut vous aider: CORS dans Rails 4 API

Il ajoute la méthode OPTIONS à la définition d’itinéraire et ajoute un filtre au contrôleur de base de l’API qui répond directement aux requêtes OPTIONS avec l’en-tête correct et définit également les en-têtes CORS corrects pour toutes les autres actions.

Ran dans ce problème avec Rails 4 et Devise. J’ai fini par utiliser la gemme Rack CORS middleware de Calvin Yu. Un excellent article de blog gratuit.

Je ne suis pas sûr de savoir quel framework frontal javascript vous utilisez (ou si vous l’êtes) puisque vous n’avez pas précisé ce que vous faites du côté client pour vous connecter à votre API Rails 4, mais je pensais append ma réponse au cas où cela aiderait quelqu’un.

J’ai rencontré exactement le même problème lors de la connexion à une API Rails 4 avec le gemme Devise d’un frontal AngularJS (les deux fonctionnaient sur des ports localhost distincts). J’essayais de me connecter à l’arrière-plan en utilisant une requête POST à ​​partir d’un formulaire AngularJS mais je continuais à obtenir une erreur 404 NOT FOUND parce que je envoyais une requête OPTIONS avec preflight. Il a fallu plus de 2 jours pour résoudre le problème.

Fondamentalement, vous devez configurer un serveur proxy pour votre front-end (Angular, Backbone, etc.) afin de vous connecter à votre API afin que votre front end pense que la requête utilise la même origine. Il existe des solutions simples pour configurer des proxies avec GruntJS. J’utilise Gulp pour mon projet avec Gulp-Connect et proxy-middleware avec la configuration suivante (basée sur la solution trouvée ici ):

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

J’espère que ça aidera quelqu’un!

J’ai rencontré le même problème et j’évalue actuellement les itinéraires suivants pour détecter d’éventuels problèmes de sécurité / performance. Ils résolvent le problème, mais …

 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"]]} 

Bien que «match» ne soit pas censé fonctionner dans Rails 4, il semble que cela fonctionne si vous le restreignez à une méthode spécifique.