モードでフェッチとパスを使用しようとしています:no-cors


166

http://catfacts-api.appspot.com/api/facts?number=99Postmanを介してこのエンドポイントをヒットすると、戻りますJSON

さらに、create-react-appを使用しており、サーバー構成の設定を避けたいと考えています。

クライアントコードでfetch同じことを実行しようとしていますが、エラーが発生します。

要求されたリソースに「Access-Control-Allow-Origin」ヘッダーがありません。したがって、オリジン ' http:// localhost:3000 'はアクセスを許可されていません。不透明な応答がニーズを満たす場合は、リクエストのモードを「no-cors」に設定して、CORSを無効にしてリソースをフェッチします。

したがって、次のようにCORSを無効にするFetchにオブジェクトを渡そうとしています。

fetch('http://catfacts-api.appspot.com/api/facts?number=99', { mode: 'no-cors'})
  .then(blob => blob.json())
  .then(data => {
    console.table(data);
    return data;
  })
  .catch(e => {
    console.log(e);
    return e;
  });

興味深いことに、私が受け取るエラーは、実際にはこの関数の構文エラーです。fetch{mode: 'no-cors'}オブジェクトを削除して別のURLを指定すると、問題なく動作するため、実際のものが壊れているかどうかはわかりません。

また、オブジェクトを渡そうとしました{ mode: 'opaque'}が、これは上から元のエラーを返します。

CORSを無効にするだけで十分です。何が欠けていますか?

回答:


290

mode: 'no-cors'魔法のように物事を動かしません。実際には、ブラウザーに「すべての状況でフロントエンドのJavaScriptコードが応答の本文とヘッダーの内容を参照しないようにブロックする」ように指示するという影響があるため、事態はさらに悪化しますもちろん、あなたはほとんどそれを望んでいません。

フロントエンドJavaScriptからのクロスオリジンリクエストで発生するのは、ブラウザーがデフォルトでフロントエンドコードがリソースのクロスオリジンにアクセスできないようにすることです。場合はAccess-Control-Allow-Origin応答している場合、ブラウザは、ブロッキングことをリラックスして、あなたのコードが応答にアクセスできるようになります。

ただし、サイトが応答を送信しない場合、Access-Control-Allow-Originフロントエンドコードはそのサイトからの応答に直接アクセスできません。特に、あなたが指定して、それを修正することはできませんmode: 'no-cors'(よ実際に確認してくださいあなたのフロントエンドのコードは、応答内容にアクセスすることはできません)。

しかし、一つのことになる仕事:あなたはを通して、あなたのリクエストを送信する場合CORSプロキシ、次のように:

var proxyUrl = 'https://cors-anywhere.herokuapp.com/',
    targetUrl = 'http://catfacts-api.appspot.com/api/facts?number=99'
fetch(proxyUrl + targetUrl)
  .then(blob => blob.json())
  .then(data => {
    console.table(data);
    document.querySelector("pre").innerHTML = JSON.stringify(data, null, 2);
    return data;
  })
  .catch(e => {
    console.log(e);
    return e;
  });
<pre></pre>

注:https://cors-anywhere.herokuapp.comを使用しようとしたときにダウンしている場合は、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


http://catfacts-api.appspot.com/api/facts?number=99Postman経由でこのエンドポイントにアクセスできます

https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORSは、Postmanで応答にアクセスできるにもかかわらず、ブラウザーがフロントエンドからクロスオリジンに応答にアクセスできない理由を説明しています応答にAccess-Control-Allow-Origin応答ヘッダーが含まれていない限り、Webアプリで実行されるJavaScriptコード。

http://catfacts-api.appspot.com/api/facts?number=99にAccess-Control-Allow-Origin応答ヘッダーがないため、フロントエンドコードがクロスオリジンの応答にアクセスすることはできません。

お使いのブラウザーは応答を正常に取得でき、Postmanやブラウザーの開発ツールでも確認できますが、ブラウザーがコードに公開するという意味ではありません。Access-Control-Allow-Origin応答ヘッダーがないため、表示されません。そのため、代わりにプロキシを使用して取得する必要があります。

プロキシは、そのサイトへの要求を作成し、応答を取得し、Access-Control-Allow-Origin応答ヘッダーとその他の必要なCORSヘッダーを追加し、それを要求元のコードに返します。そして、Access-Control-Allow-Originヘッダーが追加されたその応答がブラウザーに表示されるため、ブラウザーはフロントエンドコードが実際に応答にアクセスできるようにします。


CORSを無効にするFetchにオブジェクトを渡そうとしています

あなたはそれをしたくありません。明確に言うと、「CORSを無効にする」と言った場合、実際には同じ生成元のポリシーを無効にすることを意味しているようです。CORS自体は実際にそれを行う方法です— CORSは同じ起源のポリシーを緩和する方法であり、それを制限する方法ではありません。

しかし、とにかく、ローカル環境でのみ、ブラウザーランタイムフラグを設定してセキュリティを無効にし、安全に実行できない、またはブラウザー拡張機能をローカルにインストールして、同一生成元のポリシーを回避することができます。ローカルで状況を変えるだけです。

ローカルで何を変更しても、アプリを使用しようとする他のユーザーは引き続き同じ生成元ポリシーを実行することになり、アプリの他のユーザーに対してそれを無効にすることはできません。

mode: 'no-cors'いくつかの限られた場合を除いて、実際に使用することはほとんどありません。それでも、自分が何をしていてどのような効果があるかを正確に知っている場合に限ります。これmode: 'no-cors'は、ブラウザーに対して実際に設定されているのは、「フロントエンドのJavaScriptコードがすべての状況で応答の本文とヘッダーの内容を調べないようにする」ということです。 ほとんどの場合、それは明らかに本当に望んでいることではありません。


あなたは時に限り例として考え使用することを検討したいmode: 'no-cors'、で答えを参照してください制限が不透明な応答に適用されますか?詳細はこちら。その要点は、ケースは次のとおりです。

  • あなたが別の原点からのコンテンツリソースを作るためにはJavaScriptを使用している限られた場合には<script><link rel=stylesheet><img><video><audio><object><embed>、または<iframe>何らかの理由のために-要素(リソースの埋め込みクロスオリジンは、それらのために許可されているので、動作します)文書のマークアップに、要素のhrefor src属性としてリソースURLを使用させるだけでは、そうしたくない、またはできません。

  • リソースを使用したい唯一のことは、それをキャッシュすることです。回答で示唆したように何の制限不透明な応答に適用されますか?、実際に適用されるシナリオは、Service Workersを使用している場合です。この場合、関連するAPICache Storage APIです。

ただし、これらの限られたケースでも、注意すべき重要な問題がいくつかあります。不透明な応答に適用される制限何ですか?の回答を参照してください詳細はこちら。


オブジェクトも渡そうとしました { mode: 'opaque'}

mode: 'opaque'リクエストモードはありません。opaque代わりに、それは単にresponseのプロパティであり、ブラウザはそのno-corsモードで送信されたリクエストからのレスポンスにその不透明なプロパティを設定します。

しかし、ちなみに、不透明という言葉は、最終的に返される応答の性質についてのかなり明確なシグナルです。「不透明」とは、それが見えないことを意味します。


4
cors-anywhere単純な非製品のユースケース(つまり、公的に入手可能なデータをフェッチする)の回避策が大好きです。この回答no-corsは、そのOpaqueResponseがあまり役に立たないため、一般的ではない私の疑いを裏付けています。すなわち「非常に限られたケース」; 誰が役立つ例を私に説明できno-corsますか?
赤エンドウ

1
@TheRedPeaここで回答に対して行った更新を参照してください(そして、stackoverflow.com / questions / 52569895 /…で質問に対するコメントとして追加しました)
sideshowbarker

CORS.jsパッケージ(github.com/expressjs/cors)を使用してExpressサーバーを構成する必要がありmode: 'no-cors'、フェッチ要求から削除する必要がありました(そうでない場合、応答は空になります)
James L.

CORSプロキシは素晴らしいです。公開ファイルへのアクセスをブロックすることは「セキュリティ」対策と見なされていることに私は驚いています。それは、ハッカーの観点からすれば、とても簡単に回避できます。それこそ、まさにこれが行うことです。本当に良い俳優にとっては面倒なことです。
Seph Reed、

同じAPIを使用するさまざまなクライアントのコードを生成します。トレーニングに使用します。私はコードをシンプルに保ち、ユーザーにそれを試してもらいたいと思っています。no-crosを使用する必要があります。
profimedica

6

私と同じように、ローカルホストでLaravel APIからデータをフェッチし、それをVueフロントエンドで使用しようとしているウェブサイトを開発していて、この問題が発生した場合は、次の方法で解決しました。

  1. Laravelプロジェクトでcommandを実行しますphp artisan make:middleware Cors。これはapp/Http/Middleware/Cors.phpあなたのために作成されます。
  2. handles関数内に次のコードを追加しますCors.php

    return $next($request)
        ->header('Access-Control-Allow-Origin', '*')
        ->header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
  3. app/Http/kernel.php、次のエントリを$routeMiddleware配列に追加します。

    cors => \App\Http\Middleware\Cors::class

    (のような配列内の他のエントリがあるでしょうauthguestまた必ずでこれをやって作るなどapp/Http/kernel.php、別のがあるので、kernel.phpLaravelにすぎ)

  4. 次のように、アクセスを許可するすべてのルートのルート登録にこのミドルウェアを追加します。

    Route::group(['middleware' => 'cors'], function () {
        Route::get('getData', 'v1\MyController@getData');
        Route::get('getData2', 'v1\MyController@getData2');
    });
  5. Vueフロントエンドでは、このAPIを内mounted()ではなく関数内で呼び出すようにしてくださいdata()。また、呼び出しでURL を使用するhttp://https://、URLとともに使用してくださいfetch()

ピートヒューストンのブログ記事の全クレジット。


3

簡単な解決策:データを要求するphpファイルの最上部に次を追加します。

header("Access-Control-Allow-Origin: *");


7
これは、可能な限り最小限のセキュリティが必要な場合に非常に適しています。
異端者モンキー

画像のホットリンクはどう
ですか

1

私のための解決策は、それをサーバー側で行うことでした

C#WebClientライブラリを使用してデータ(私の場合は画像データ)を取得し、クライアントに送り返しました。おそらく、選択したサーバー側言語に非常によく似たものがあります。

//Server side, api controller

[Route("api/ItemImage/GetItemImageFromURL")]
public IActionResult GetItemImageFromURL([FromQuery] string url)
{
    ItemImage image = new ItemImage();

    using(WebClient client = new WebClient()){

        image.Bytes = client.DownloadData(url);

        return Ok(image);
    }
}

あなたはあなた自身のユースケースが何であれそれを微調整することができます。要点はclient.DownloadData()CORSエラーなしで機能します。通常、CORSの問題はWebサイト間でのみ発生するため、サーバーから「クロスサイト」リクエストを発行しても問題ありません。

その場合、Reactフェッチ呼び出しは次のように簡単です。

//React component

fetch(`api/ItemImage/GetItemImageFromURL?url=${imageURL}`, {            
        method: 'GET',
    })
    .then(resp => resp.json() as Promise<ItemImage>)
    .then(imgResponse => {

       // Do more stuff....
    )}

1

非常に簡単な解決策(設定に2分)は、ローカルのssl-proxyパッケージを使用することですnpm

使い方は簡単です
。1.パッケージをインストールします npm install -g local-ssl-proxy
。2. local-serverマスクを実行しながら、local-ssl-proxy --source 9001 --target 9000

PS:交換する--target 9000-- "number of your port"して--source 9001--source "number of your port +1"


1
実際の電話デバイスでのアプリの使用に問題があります。あなたの解決策はこの場合に役に立ちますか?
Hamid Araghi

@HamidAraghi開発の目的で、プロキシサーバーは実際にエラーの影響を受けるデバイス上で実行される必要があるため、私は今仮定すると思います
volna
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.