この回答は多くの範囲をカバーしているため、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そのプロキシを介して行われるように要求すると、次のようになります。
- リクエストをに転送し
https://example.com
ます。
- からの応答を受信し
https://example.com
ます。
Access-Control-Allow-Origin
ヘッダーを応答に追加します。
- ヘッダーを追加した応答を、要求元のフロントエンドコードに返します。
その後、ブラウザはフロントエンドコードが応答にアクセスすることを許可します。これは、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
を含むクロスオリジンの受信をオプトインしているかどうかを判断します。Authorization
Content-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_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
、サーバーOPTIONS
が405または501または200または204以外の何かでその要求に応答する場合、または必要なもので応答しない場合、フロントエンドJavaScriptコードからそのサーバーに直接要求を送信することはできません。応答ヘッダー。
問題のケースのプリフライトのトリガーを回避する方法は次のとおりです。
- サーバーが
Authorization
要求ヘッダーを必要とせず、代わりに(たとえば)POST
要求の本文に埋め込まれた認証データまたはクエリパラメーターに依存している場合
- サーバーが
POST
本文にContent-Type: application/json
メディアタイプを必要とせず、代わりに名前が付けられたパラメーター(または何でも)のようにPOST
本文を受け入れ、その値がJSONデータである場合application/x-www-form-urlencoded
json
「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-*
ヘッダはレスポンスヘッダ。リクエストでそれらを送信することは決してありません。唯一の効果は、ブラウザにプリフライトを実行させることです。