REST APIからデータを取得しようとしたときに、リクエストされたリソースに「Access-Control-Allow-Origin」ヘッダーがありません


469

HP AlmのREST APIからデータをフェッチしようとしています。それは小さなカールスクリプトでかなりうまく機能します-私は私のデータを取得します。

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

Fetch 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属性によって制御されます。

回答:


824

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

  • CORSプロキシを使用して「Access-Control-Allow-Originヘッダーがない」問題を回避する方法
  • 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分でデプロイする方法については、以下を参照してください。

リクエストURLを取り、それを変えるために成功応答にアクセスすることができます上記の2番目のコードスニペットhttps://cors-anywhere.herokuapp.com/https://example.comだけプロキシ原因URLでそれを前に置く-byそのプロキシを介して行われるように要求すると、次のようになります。

  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アカウントを取得することを検討してください(まだダウンしていない場合)。または上記の手順を実行して独自のCORS AnywhereサーバーをHerokuにデプロイするには、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を含むクロスオリジンの受信をオプトインしているかどうかを判断します。AuthorizationContent-Type: application/json

それは小さなカールスクリプトでかなりうまく機能します-私は私のデータを取得します。

で適切にテストする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_inURLに置き換えられます。

ブラウザがその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)である必要があります。それが他のステータスコードの場合、ブラウザはそこですぐに停止します。

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

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

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

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

「Access-Control-Allow-Originヘッダーをワイルドカードにすることはできません」の問題を修正する方法

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

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

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

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

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

add_header Access-Control-Allow-Origin $http_origin

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


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

このChrome CORSプラグインAccess-Control-Allow-Origin: *は、ブラウザが表示する応答にヘッダーを挿入するだけです。プラグインの方が賢い場合は、その偽のAccess-Control-Allow-Origin応答ヘッダーの値を、フロントエンドのJavaScriptコードの実際の生成元に設定します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-*ヘッダはレスポンスヘッダ。リクエストでそれらを送信することは決してありません。唯一の効果は、ブラウザにプリフライトを実行させることです。


1
したがって、URLは次のようになります。127.0.0.1 :9999 / 127.0.0.1:5000 with cors?
daniel.lozynski

あなたは、あなた自身のインスタンス実行している場合github.com/Rob--W/cors-anywhereのでコードを127.0.0.1:9999、あなたはへの要求を作りたい127.0.0.1:5000はい、
sideshowbarker

4
素晴らしい答え、私の問題は、OPTIONS要求に応答していないリモートサーバーたので、年齢のように思えた何のための要求とヘッダを約いじった後、私は、ヘッダーを削除することで、それを解決Content-TypeしてAccess-Control-Allow-Origin-ありがとうございました!
Morvael

1
自分が制御するプロキシでない限り、プロキシを使用するのは好きではありません。そうしないと、信頼できないサードパーティを介してデータをフェッチし、改ざんの
危険性があります。– DaveMongoose

1
これは詳細ですばらしい回答です。テスト時に私が個人的に行ったのは、無効化Webセキュリティフラグ付きのオープンクロムでしたが、うまくいきました。 open /Applications/Google\ Chrome.app --args --disable-web-security --user-data-dir
Karun、

101

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

Spring RESTサービスをホストしている場合は、Spring FrameworkのCORSサポートのブログ投稿で見つけることができます。

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

  1. Node.jsサーバーを停止します。
  2. npm install cors --save
  3. server.jsに次の行を追加します

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

4
何の問題もなく動作しました...スプリングリソースリンクで非常に役に立ちました。ありがとうございます
Rajesh Mbm

4
including the port number:(
scottysseus

1
本当に役立つuは私の日を作った
kunal pal

ポート番号は私の命を救った
アシャド

これまで
スタック

47

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

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

これらのヘッダーは、リクエストではなくレスポンスに属します。したがって、次の行を含めて削除します。

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

4
これが一番の答えになるはずです-私はCORSをバイパスするという考え、特にサードパーティを介してルーティングすることを嫌います。
DaveMongoose

ねえ、「Header()」って何?
ミツ

@mitsu次の行を参照する場合:let headers = new Headers(); 上記の場合、それはhttp要求または応答ヘッダーでアクションを実行するフェッチAPIのインターフェースです。developer.mozilla.org/en-US/docs/Web/API/Headersにアクセスて、詳細と使用例を入手してください。
Lex Soft

1
明確で正確な答え..その論理的かつ正確に問題に対処します。-Thx
Dhammika

7

私の場合、私は以下の解決策を使用します

フロントエンドまたは角度

post(
    this.serverUrl, dataObjToPost,
    {
      headers: new HttpHeaders({
           'Content-Type':  'application/json',
         })
    }
)

バックエンド(私はphpを使用しています)

header("Access-Control-Allow-Origin: http://localhost:4200");
header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
header("Access-Control-Allow-Headers: Content-Type, Authorization");

$postdata = file_get_contents("php://input");
$request = json_decode($postdata);
print_r($request);

2

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

バックエンドで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/*})



1

使用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               

1

私の場合、Webサーバーが「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

私はSpring RESTを使用していて、AllowedMethodsを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");
                }
            };
        }

-1

私のローカルでこのエラーが発生していました。私は管理者としてVisual Studioを実行しましたが、解決しました。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.