web-dev-qa-db-ja.com

Rails CORSプリフライトオプションリクエストで404で応答します

Rails 4を使用して一連のサービスを作成しています。これをJavaScriptブラウザーアプリケーションで使用しています。Cross-OriginGETSは正常に機能していますが、私のPOSTは404エラー。少なくとも、それが起こっていると思います。コンソールに表示されるエラーは次のとおりです。これは、MacではChrome 31.0.1650.63です。

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

CORSを有効にするための指示を高低で検索しましたが、困惑しています。通常の推奨事項は、このようなものをアプリケーションコントローラーに配置することです。

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

OPTIONSリクエストが入ったときにこのアクションにリダイレクトするroutes.rbのある種のルートが続きます。

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

'match'ディレクティブはRails 4では動作しません。そのため、次のようにPOSTSに直接一致させようと試みました。

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

しかし、まだ機能しません。 GETリクエストが機能しているので、私が見逃しているのはOPTIONSリクエストの正しいルートだと思っています。しかし、考えられるすべてのルートを試してみましたが、リクエストを通過させるものは何もないようです。

cyu/rack-cors もインストールしてみましたが、これは同じ結果になります。

誰が私が間違っているのか知っていますか?

44
Rolandus

rack-cors gemを使用した解決策を次に示します。他の人が述べたように、使用しているフロントエンドフレームワークと実際のリクエストがどのように見えるかに関してはあまり詳しく説明しませんでした。したがって、以下はあなたには当てはまらないかもしれませんが、誰かの助けになることを願っています。

私の場合、gemはPUT(またはPATCHまたはDELETE)を使用するまで正常に機能しました。

ブラウザの開発者コンソールを見る場合、リクエストヘッダーを見てください。次のような行が必要です。

Access-Control-Request-Method: PUT

注意すべき重要なことは、methodsに渡すresourceAccess-Control-Request-Methodに対するものであり、プリフライトチェックの後に来るリクエストメソッドではないことです。

注意するすべてのメソッドを含む:methods => [:get, :post, :options, :delete, :put, :patch]があることに注意してください。

したがって、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
24
Tyler Collier

作業中Rails 3.2.11。

置いた

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

routes.rbファイル内。重要なのは、(routes.rbファイルの上に)最優先としてそれを置くことでした。 publicが利用できるようにそのアクションを作成しました:

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

アプリケーションコントローラーのフィルター:

 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
11
ancajic

はい、他の人が指摘しているように、おそらくこれをもっとうまくやるためのGEMがあります。しかし、私は 元のブログ投稿 で指摘された方法がcorsコードで非常に好きだったので、Rails 4そのコードを使用している場合の解決策。

Routes.rbで:

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

My_method_nameコントローラーで:

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

それに加えて他のコードがある限り:

before_filter :cors_preflight_check
after_filter :cors_set_access_control_headers
...

次に、Rails 4。

6

おそらく、この要点はあなたを助けることができます: CORS in Rails 4 APIs

OPTIONSメソッドをルート定義に追加し、正しいヘッダーでOPTIONSリクエストに直接応答するAPIベースコントローラーにフィルターを追加し、他のすべてのアクションに正しいCORSヘッダーを設定しますも。

3
dhoelzgen

Rails 4 and Deviseでこの問題に飛びつきました。私はRack CORS middlewaregem by Calvin Yu。素晴らしい無料のブログ 記事

2
Tom Doe

Rails 4に接続するためにクライアント側で何をしているのかを詳しく説明しなかったため、使用しているJavaScriptフロントエンドフレームワークが不明です。 API、しかし私はそれが誰かを助ける場合に私の答えを追加すると思いました。

AngularJSフロントエンドからDevise gemを使用してRails 4 APIに接続している間(両方とも別々のlocalhostポートで実行されていました)、まったく同じ問題に遭遇しました。 AngularJSフォームからのPOSTリクエストを使用しますが、プリフライトでOPTIONSリクエストを送信していたため、404 NOT FOUNDエラーが表示され続けました。修正方法を見つけるのに2日以上かかりました問題。

基本的に、APIに接続するには、フロントエンド(Angular、Backboneなど)のプロキシサーバーをセットアップして、リクエストが同じOriginを使用しているとフロントエンドが判断するようにする必要があります。 GruntJSを使用してプロキシを設定するための 簡単なソリューション があります。私のプロジェクトでは、Gulp-Connectとproxy-middlewareを使用して、次のセットアップでGulpを使用しています(見つかったソリューションに基づいて 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);
            })() ];
        }
      });
    });

これが誰かの助けになることを願っています!

1
po3t

私は同じ問題にぶつかりました。現在、考えられるセキュリティ/パフォーマンスの問題について次のルートを評価しています。彼らは問題を解決しますが...

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

Rails 4では動作しないはずの 'match'にもかかわらず、明らかにdoes特定のメソッドに制限すると動作します。

1
RonLugge