web-dev-qa-db-ja.com

要求されたリソースに 'Access-Control-Allow-Origin'ヘッダーが存在しません REST API

HP AlmのREST AP​​Iからデータを取得しようとしています。それは小さなカールスクリプトでかなりうまく動作します - 私は自分のデータを取得します。

JavaScriptでそれをやるには、fetchとES6(多かれ少なかれ)がもっと大きな問題になりそうです。私はこのエラーメッセージを受け取り続けます:

取得APIを読み込めません。プリフライト要求への応答がアクセス制御チェックに合格しなかった:要求されたリソースに 'Access-Control-Allow-Origin'ヘッダーが存在しない。オリジン ' http://127.0.0.1:3000 'はなので、アクセスは許可されていません。応答のHTTPステータスコードは501です。不透明な応答がニーズを満たす場合は、要求のモードを 'no-cors'に設定して、CORSを無効にしてリソースを取得します。

これは、自分のローカルホスト内からそのデータを取得しようとしているためで、CORSを使用する必要があることを理解しています。今、私は実際にそれをしたと思いました、しかし、どういうわけかそれは私がヘッダーに書くものを無視するか、問題は別のものですか? 

では、実装上の問題はありますか?私はそれを間違っていますか?残念ながら、サーバーのログを確認することはできません。私は本当にここで少し立ち往生しています。

function performSignIn() {

  let headers = new Headers();

  headers.append('Content-Type', 'application/json');
  headers.append('Accept', 'application/json');

  headers.append('Access-Control-Allow-Origin', 'http://localhost:3000');
  headers.append('Access-Control-Allow-Credentials', 'true');

  headers.append('GET', 'POST', 'OPTIONS');

  headers.append('Authorization', 'Basic ' + base64.encode(username + ":" + password));

  fetch(sign_in, {
      //mode: 'no-cors',
      credentials: 'include',
      method: 'POST',
      headers: headers
    })
    .then(response => response.json())
    .then(json => console.log(json))
    .catch(error => console.log('Authorization failed : ' + error.message));
}

Chromeを使用しています。そのChrome CORSプラグインを使用してみましたが、それから別のエラーメッセージが表示されます。

要求の認証情報モードが 'include'の場合、応答内の 'Access-Control-Allow-Origin'ヘッダーの値をワイルドカード '*'にすることはできません。オリジン ' http://127.0.0.1:3000 'はアクセスが許可されていません。 XMLHttpRequestによって開始された要求の信任状モードは、withCredentials属性によって制御されます。

183
daniel.lozynski

この答えは多くの点をカバーしているため、3つの部分に分かれています。

  • CORSプロキシを使用して回避する方法「No Access-Control-Allow-Origin header」問題
  • CORSプリフライトを回避する方法
  • 修正方法「Access-Control-Allow-Originヘッダーはワイルドカードにしないでください」問題

CORSプロキシを使用して回避する方法「Access-Control-Allow-Originヘッダーなし」問題

フロントエンドJavaScriptコードがリクエストを送信しているサーバーを制御しない場合、そのサーバーからの応答の問題は、必要なAccess-Control-Allow-Originヘッダーがないことだけです。 CORSプロキシを介してリクエストを作成します。その仕組みを示すために、まず、CORSプロキシを使用しないコードをいくつか紹介します。

const url = "https://example.com"; // site that doesn’t send Access-Control-*
fetch(url)
.then(response => response.text())
.then(contents => console.log(contents))
.catch(() => console.log("Can’t access " + url + " response. Blocked by browser?"))

catchブロックがヒットする理由は、ブラウザーがそのコードがhttps://example.comから返される応答にアクセスするのを防ぐためです。そして、ブラウザーがそれを行う理由は、応答にAccess-Control-Allow-Origin応答ヘッダーがないことです。

さて、これはまったく同じ例ですが、CORSプロキシが追加されているだけです。

const proxyurl = "https://cors-anywhere.herokuapp.com/";
const url = "https://example.com"; // site that doesn’t send Access-Control-*
fetch(proxyurl + url) // https://cors-anywhere.herokuapp.com/https://example.com
.then(response => response.text())
.then(contents => console.log(contents))
.catch(() => console.log("Can’t access " + url + " response. Blocked by browser?"))

注:https://cors-anywhere.herokuapp.comを試してみるとダウンまたは利用できない場合は、Herokuで独自のCORS Anywhereサーバーをデプロイする方法について以下を参照してくださいわずか2〜3分で。

上記の2番目のコードスニペットは、リクエストURLを取得し、プレフィックスを付けるだけで https://cors-anywhere.herokuapp.com/https://example.com に変更するため、レスポンスに正常にアクセスできます。プロキシURLを使用して、リクエストがそのプロキシを介して行われるようにします。

  1. リクエストをhttps://example.comに転送します。
  2. https://example.comから応答を受け取ります。
  3. Access-Control-Allow-Originヘッダーを応答に追加します。
  4. ヘッダーを追加して、その応答を要求元のフロントエンドコードに返します。

ブラウザは、Access-Control-Allow-Origin応答ヘッダーを持つ応答がブラウザに表示されるため、フロントエンドコードが応答にアクセスできるようにします。

https://github.com/Rob--W/cors-anywhere/ のコードを使用して、独自のプロキシを簡単に実行できます。
5つのコマンドを使用して、文字通りわずか2〜3分でHerokuに独自のプロキシを簡単にデプロイすることもできます。

git clone https://github.com/Rob--W/cors-anywhere.git
cd cors-anywhere/
npm install
heroku create
git Push heroku master

これらのコマンドを実行すると、たとえば https://cryptic-headland-94862.herokuapp.com/ で実行される独自のCORS Anywhereサーバーになります。したがって、リクエストURLの前にhttps://cors-anywhere.herokuapp.comを付けるのではなく、独自のインスタンスのURLを前に付けます。例: https://cryptic-headland-94862.herokuapp.com/https://example.com .

そのため、https://cors-anywhere.herokuapp.comを使用しようとすると、ダウンしていることがわかります(場合によっては) 、Herokuアカウントを取得することを検討し(まだ取得していない場合)、Herokuに独自のCORS Anywhereサーバーをデプロイするために上記の手順を2〜3分実行します。

いずれにせよ、自分で実行するか、 https://cors-anywhere.herokuapp.com または他のオープンプロキシを使用するかどうかに関係なく、このソリューションは、ブラウザがCORSプリフライトを実行するトリガーであっても機能しますOPTIONSリクエスト—その場合、プロキシはプリフライトを成功させるために必要なAccess-Control-Allow-HeadersおよびAccess-Control-Allow-Methodsヘッダーも送り返します。


CORSプリフライトを回避する方法

質問のコードは、Authorizationヘッダーを送信するため、CORSプリフライトをトリガーします。

https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Preflighted_requests

それがなくても、Content-Type: application/jsonヘッダーもプリフライトをトリガーします。

「プリフライト」の意味:ブラウザーが質問のコードでPOSTを試行する前に、最初にOPTIONSリクエストをサーバーに送信し、サーバーが受信を選択しているかどうかを判断しますPOSTおよびContent-Type: application/jsonヘッダーを含むクロスオリジンAuthorization.

小さなcurlスクリプトで非常にうまく機能します-データを取得します。

curlで適切にテストするには、ブラウザが送信するプリフライトOPTIONSリクエストをエミュレートする必要があります。

curl -i -X OPTIONS -H "Origin: http://127.0.0.1:3000" \
    -H 'Access-Control-Request-Method: POST' \
    -H 'Access-Control-Request-Headers: Content-Type, Authorization' \
    "https://the.sign_in.url"

https://the.sign_in.urlを実際のsign_in URLに置き換えてください。

ブラウザがOPTIONSリクエストから確認する必要がある応答には、次のようなヘッダーが含まれている必要があります。

Access-Control-Allow-Origin:  http://127.0.0.1:3000
Access-Control-Allow-Methods: POST
Access-Control-Allow-Headers: Content-Type, Authorization

OPTIONSレスポンスにこれらのヘッダーが含まれていない場合、ブラウザはそこで停止し、POSTリクエストを送信することさえ試みません。また、応答のHTTPステータスコードは2xx(通常は200または204)である必要があります。他のステータスコードの場合、ブラウザはそこで停止します。

問題のサーバーは、OPTIONSリクエストに501ステータスコードで応答しています。これは、OPTIONSリクエストのサポートを実装していないことを示しているようです。この場合、他のサーバーは通常、405「メソッドは許可されていません」ステータスコードで応答します。

そのため、サーバーがPOST要求に405または501または200以外の何かで応答する場合、フロントエンドJavaScriptコードからそのサーバーにOPTIONS要求を直接送信することはできません。 204または必要な応答ヘッダーで応答しない場合。

問題のケースのプリフライトのトリガーを回避する方法は次のとおりです。

  • サーバーがAuthorizationリクエストヘッダーを必要とせず、代わりに(たとえば)POSTリクエストの本文に埋め込まれた認証データまたはクエリパラメーターに依存している場合
  • サーバーがPOSTボディにContent-Type: application/jsonメディアタイプを持つことを要求しなかったが、代わりにPOSTボディをjsonというパラメーターを持つapplication/x-www-form-urlencodedとして受け入れた場合またはその値がJSONデータである

修正方法「Access-Control-Allow-Originヘッダーはワイルドカードであってはなりません」問題

別のエラーメッセージが表示されます。

リクエストの認証情報モードが「include」の場合、レスポンスの「Access-Control-Allow-Origin」ヘッダーの値はワイルドカード「*」であってはなりません。 Origin ' http://127.0.0.1:30 'はアクセスを許可されていません。 XMLHttpRequestによって開始された要求の資格情報モードは、withCredentials属性によって制御されます。

資格情報を含むリクエストの場合、Access-Control-Allow-Origin応答ヘッダーの値が*の場合、ブラウザはフロントエンドJavaScriptコードが応答にアクセスすることを許可しません。代わりに、その場合の値は、フロントエンドコードのOrigin http://127.0.0.1:3000と正確に一致する必要があります。

MDN HTTPアクセス制御(CORS)の記事の 認証されたリクエストとワイルドカード をご覧ください。

リクエストを送信するサーバーを制御する場合、このケースに対処する一般的な方法は、サーバーを設定してOriginリクエストヘッダーの値を取得し、その値にエコー/反映することです。 Access-Control-Allow-Origin応答ヘッダーのたとえば、nginxの場合:

add_header Access-Control-Allow-Origin $http_Origin

しかし、それはほんの一例です。他の(Web)サーバーシステムは、Origin値をエコーする同様の方法を提供します。


Chromeを使用しています。 Chrome CORSプラグインも使用してみました

Chrome CORSプラグインは、ブラウザが見る応答にAccess-Control-Allow-Origin: *ヘッダーを単純に挿入するようです。プラグインがよりスマートな場合、プラグインは、その偽のAccess-Control-Allow-Origin応答ヘッダーの値を、フロントエンドJavaScriptコードの実際のOrigin http://127.0.0.1:3000に設定します。

そのため、テスト用であっても、そのプラグインを使用しないでください。気が散るだけです。ブラウザからフィルタリングを行わずにサーバーから取得する応答をテストする場合は、上記のcurl -Hを使用することをお勧めします。


質問のfetch(…)リクエストのフロントエンドJavaScriptコードに関して:

headers.append('Access-Control-Allow-Origin', 'http://localhost:3000');
headers.append('Access-Control-Allow-Credentials', 'true');

それらの行を削除します。 Access-Control-Allow-*ヘッダーはresponseヘッダーです。リクエストで送信することはありません。唯一の効果は、ブラウザでプリフライトを実行することです。

507
sideshowbarker

このエラーは、ポート番号を含め、クライアントURLとサーバーURLが一致しない場合に発生します。この場合、クロスオリジンリソース共有であるCORSに対してサービスを有効にする必要があります。

Spring RESTサービスをホストしている場合は、ブログ投稿Spring FrameworkでのCORSサポートにあります。

Node.jsサーバーを使用してサービスをホストしている場合は、

  1. Node.jsサーバーを停止します。
  2. npmインストールコア
  3. Server.jsに以下の行を追加します。

    var cors = require('cors')
    
    app.use(cors()) // Use this after the variable declaration
    
39
Rakesh

フロントエンドにrequestヘッダーとして次のコードを追加したため、問題が発生しました。

headers.append('Access-Control-Allow-Origin', 'http://localhost:3000');
headers.append('Access-Control-Allow-Credentials', 'true');

これらのヘッダはresponseに属し、requestではありません。だから 削除 それら、行を含む: 

headers.append('GET', 'POST', 'OPTIONS');

あなたのリクエストは 'Content-Type:application/json'を持っていたので、CORSプリフライトと呼ばれるものを引き起こしました。これにより、ブラウザはOPTIONSメソッドでリクエストを送信しました。詳細については CORSプリフライト を参照してください。 
したがって、あなたの バックエンド では、次のようなレスポンスヘッダを返すことでこのプリフライトリクエストを処理しなければなりません。

Access-Control-Allow-Origin : http://localhost:3000
Access-Control-Allow-Credentials : true
Access-Control-Allow-Methods : GET, POST, OPTIONS
Access-Control-Allow-Headers : Origin, Content-Type, Accept

もちろん、実際の構文はバックエンドに使用するプログラミング言語によって異なります。

あなたのフロントエンドでは、それはそのようになるはずです:

function performSignIn() {
    let headers = new Headers();

    headers.append('Content-Type', 'application/json');
    headers.append('Accept', 'application/json');
    headers.append('Authorization', 'Basic ' + base64.encode(username + ":" +  password));
    headers.append('Origin','http://localhost:3000');

    fetch(sign_in, {
        mode: 'cors',
        credentials: 'include',
        method: 'POST',
        headers: headers
    })
    .then(response => response.json())
    .then(json => console.log(json))
    .catch(error => console.log('Authorization failed : ' + error.message));
}
1
Lex Soft

dataType: 'jsonp'を使うことは私のために働きました。

   async function get_ajax_data(){
       var _reprojected_lat_lng = await $.ajax({
                                type: 'GET',
                                dataType: 'jsonp',
                                data: {},
                                url: _reprojection_url,
                                error: function (jqXHR, textStatus, errorThrown) {
                                    console.log(jqXHR)
                                },
                                success: function (data) {
                                    console.log(data);

                                    // note: data is already json type, you
                                    //       just specify dataType: jsonp
                                    return data;
                                }
                            });


 } // function               
0
hoogw

これを削除してください。

credentials: 'include',
0

私の場合、ウェブサーバーは「OPTIONS」メソッドを禁止していました

オプションの方法については、Webサーバーを確認してください

「webtier」を使用しています

/www/webtier/domains/[domainname]/config/fmwconfig/components/OHS/VCWeb1/httpd.conf

<IfModule mod_rewrite.c>
  RewriteEngine on
  RewriteCond %{REQUEST_METHOD} ^OPTIONS
  RewriteRule .* . [F]
</IfModule>

への変更

<IfModule mod_rewrite.c>
  RewriteEngine off
  RewriteCond %{REQUEST_METHOD} ^OPTIONS
  RewriteRule .* . [F]
</IfModule>
0
Juneho Nam

私の2セント... 「Access-Control-Allow-Originヘッダーがない」問題を回避するためにCORSプロキシを使用する方法について

バックエンドでphpを使っている人にとっては、 "CORSプロキシ"のデプロイはとても簡単です。

  1. 以下の内容で 'no-cors.php'という名前のファイルを作成します。

    $ URL = $ _GET ['url']; echo json_encode(file_get_contents($ URL)); die();

  2. フロントエンドで、次のようにします。

    fetch( ' https://example.com/no-cors.php ' + '?url =' + url).then(response => {/ Handle Response /})

0
Yair Levy

私はSpring RESTを使用して作業していましたが、それを解決してAllowMedhodをWebMvcConfigurerに追加しました。

@Value( "${app.allow.origins}" )
    private String allowOrigins;    
@Bean
public WebMvcConfigurer corsConfigurer() {
            System.out.println("allow Origin: "+allowOrigins);
            return new WebMvcConfigurerAdapter() {
                @Override
                public void addCorsMappings(CorsRegistry registry) {
                    registry.addMapping("/**")
                    //.allowedOrigins("http://localhost")
                    .allowedOrigins(allowOrigins)
                    .allowedMethods("PUT", "DELETE","GET", "POST");
                }
            };
        }
0
Jorge Dominguez